home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / comm / tcp / samba_2.0.6.lha / source / amiga / amiga.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-12-25  |  156.1 KB  |  8,081 lines

  1. /*
  2.  * $Id: amiga.c 1.13 1999/12/25 11:31:10 olsen Exp olsen $
  3.  *
  4.  * :ts=4
  5.  *
  6.  * AmigaOS wrapper routines for Samba 2.0.0, using the AmiTCP V4 API
  7.  * and the SAS/C V6.58 compiler.
  8.  *
  9.  * Copyright (C) 1999 by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. /******************************************************************************/
  27.  
  28. #include <bsdsocket/socketbasetags.h>
  29. #include <libraries/usergroup.h>
  30.  
  31. #include <intuition/intuition.h>
  32. #include <libraries/locale.h>
  33. #include <exec/execbase.h>
  34. #include <exec/memory.h>
  35. #include <dos/dosextens.h>
  36. #include <dos/dostags.h>
  37. #include <devices/timer.h>
  38. #include <utility/date.h>
  39.  
  40. #include <clib/usergroup_protos.h>
  41. #include <clib/socket_protos.h>
  42.  
  43. #include <clib/intuition_protos.h>
  44. #include <clib/utility_protos.h>
  45. #include <clib/locale_protos.h>
  46. #include <clib/timer_protos.h>
  47. #include <clib/alib_protos.h>
  48. #include <clib/exec_protos.h>
  49. #include <clib/dos_protos.h>
  50.  
  51. #include <sys/socket.h>
  52. #include <sys/ioctl.h>
  53. #include <sys/time.h>
  54. #include <sys/dir.h>
  55.  
  56. #include <net/if.h>
  57.  
  58. #include <constructor.h>
  59. #include <stdarg.h>
  60. #include <stdlib.h>
  61. #include <string.h>
  62. #include <unistd.h>
  63. #include <signal.h>
  64. #include <utime.h>
  65. #include <errno.h>
  66. #include <stdio.h>
  67. #include <fcntl.h>
  68. #include <inetd.h>
  69. #include <stat.h>
  70. #include <ios1.h>
  71. #include <dos.h>
  72.  
  73. #include <pragmas/usergroup_pragmas.h>
  74. #include <pragmas/socket_pragmas.h>
  75.  
  76. #include <pragmas/exec_sysbase_pragmas.h>
  77. #include <pragmas/intuition_pragmas.h>
  78. #include <pragmas/utility_pragmas.h>
  79. #include <pragmas/locale_pragmas.h>
  80. #include <pragmas/timer_pragmas.h>
  81. #include <pragmas/dos_pragmas.h>
  82.  
  83. /******************************************************************************/
  84.  
  85. /* This is for the "iface_struct" definition. */
  86. #include "interfaces.h"
  87.  
  88. /******************************************************************************/
  89.  
  90. /*#define DEBUG*/
  91. #include "Assert.h"
  92.  
  93. /******************************************************************************/
  94.  
  95. STATIC VOID ReportProblem(const char *fmt, ...);
  96. STATIC VOID ForbidDOSCleanup(VOID);
  97. STATIC VOID PermitDOS(VOID);
  98. STATIC VOID ForbidDOS(VOID);
  99. STATIC VOID UnblockDescriptorCleanup(VOID);
  100. STATIC BOOL IsDescriptorNonblocking(int fd);
  101. STATIC VOID BlockDescriptor(int fd);
  102. STATIC VOID UnblockDescriptor(int fd);
  103. STATIC VOID SaveDescriptorCleanup(VOID);
  104. STATIC VOID RestoreDescriptor(struct UFB *ufb);
  105. STATIC BOOL SaveDescriptor(struct UFB *ufb);
  106. STATIC VOID UnmangleName(char **namePtr, struct MangleInfo *mi);
  107. STATIC int MangleName(char ** namePtr,struct MangleInfo * mi);
  108. STATIC VOID CloseUnlinkUnlockCleanup(VOID);
  109. STATIC VOID OpenDirCleanup(VOID);
  110. STATIC int TranslateRelativePath(char **namePtr, char *replace, int maxReplaceLen);
  111. STATIC VOID MapDescriptorSets(const fd_set *input_fds, int num_input_fds, fd_set *socket_fds, int *max_socket_fd_ptr, fd_set *file_fds, int *max_file_fd_ptr);
  112. STATIC VOID RemapDescriptorSets(const fd_set *socket_fds, int max_socket_fd, const fd_set *file_fds, int max_file_fd, fd_set *output_fds, int num_output_fds);
  113. STATIC VOID ConvertFileInfoToStat(struct MsgPort *port, struct FileInfoBlock *fib, struct stat *st);
  114. STATIC BOOL do_match(STRPTR str, STRPTR regexp);
  115. STATIC VOID nstrcpy_blank(const size_t maxSize, char *to, const char *from);
  116. STATIC BOOL SetFileSocket(FILE *stream, int sockfd);
  117. STATIC VOID DaemonInit(VOID);
  118. STATIC struct tm *ConvertTime(ULONG seconds);
  119. STATIC VOID MapIoErrToErrno(VOID);
  120. STATIC int MapFileNameAmigaToUnix(const char *amiga, char *unix, int maxUnixLen);
  121. STATIC VOID FlushSTDOUT(VOID);
  122. STATIC VOID CleanupSambaSemaphore(VOID);
  123. STATIC BOOL SetupSambaSemaphore(VOID);
  124. STATIC VOID RemoveLockedRegionNode(struct UFB *ufb, LONG start, LONG stop);
  125. STATIC VOID DeleteLockedRegionNode(struct LockedRegionNode *lrn);
  126. STATIC LONG CreateLockedRegionNode(struct LockedRegionNode **resultPtr);
  127. STATIC VOID DeleteFileLockNode(struct FileLockNode *fln);
  128. STATIC LONG CreateFileLockNode(struct UFB *ufb, struct FileLockNode **resultPtr);
  129. STATIC LONG FindFileLockNodeByFileHandle(BPTR fileHandle, struct FileLockNode **resultPtr);
  130. STATIC VOID FindFileLockNodeByDrawerAndName(BPTR parentDir, STRPTR fileName, struct FileLockNode **resultPtr);
  131. STATIC VOID CleanupFileLocks(int fd);
  132. STATIC int HandleFileLocking(int cmd, struct flock *l, struct UFB *ufb);
  133. STATIC struct LockedRegionNode *FindCollidingRegion(struct FileLockNode *fln, LONG start, LONG stop, BOOL shared);
  134.  
  135. /******************************************************************************/
  136.  
  137. int amiga_sigmask(int signum);
  138. int amiga_sigblock(int sigmask);
  139. int amiga_sigsetmask(int sigmask);
  140. int amiga_unlink(char *name);
  141. int amiga_open(char *name, int mode, int prot);
  142. int amiga_chdir(char *path);
  143. DIR *amiga_opendir(char *dirName);
  144. VOID amiga_closedir(DIR *dir);
  145. struct dirent *amiga_readdir(DIR *dir);
  146. int amiga_mkdir(char *name, int mode);
  147. int amiga_rmdir(char *name);
  148. int amiga_creat(char *name, int prot);
  149. FILE *amiga_fopen(char *name, char *mode);
  150. int amiga_rename(char *old, char *new);
  151. char *amiga_getcwd(char *buf, size_t size);
  152. int amiga_ftruncate(int fd, off_t size);
  153. int amiga_accept(int sockfd, struct sockaddr *cliaddr, int *addrlen);
  154. int amiga_bind(int sockfd, struct sockaddr *name, int namelen);
  155. int amiga_close(int fd);
  156. int amiga_connect(int sockfd, struct sockaddr *name, int namelen);
  157. int amiga_getpeername(int sockfd, struct sockaddr *name, int *namelen);
  158. int amiga_getsockopt(int sockfd, int level, int optname, VOID *optval, int *optlen);
  159. int amiga_ioctl(int fd, unsigned long request, char *arg);
  160. int amiga_listen(int sockfd, int backlog);
  161. int amiga_read(int fd, VOID *data, unsigned int size);
  162. int amiga_recvfrom(int sockfd, VOID *buff, int len, int flags, struct sockaddr *from, int *fromlen);
  163. int amiga_select(int num_fds, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds, struct timeval *timeout);
  164. int amiga_sendto(int sockfd, VOID *buff, int len, int flags, struct sockaddr *to, int tolen);
  165. int amiga_setsockopt(int sockfd, int level, int optname, VOID *optval, int optlen);
  166. int amiga_socket(int domain, int type, int protocol);
  167. int amiga_write(int fd, VOID *data, unsigned int size);
  168. int amiga_stat(char *name, struct stat *st);
  169. int amiga_lstat(char *name, struct stat *statstruct);
  170. int amiga_fstat(int fd, struct stat *st);
  171. int amiga_chmod(char *name, int mode);
  172. int amiga_dup(int fd);
  173. int amiga_dup2(int old_fd, int new_fd);
  174. int amiga_chown(char *name, uid_t uid, gid_t gid);
  175. int amiga_setegid(gid_t g);
  176. int amiga_seteuid(uid_t u);
  177. int amiga_gettimeofday(struct timeval *tv);
  178. int amiga_utime(char *name, struct utimbuf *time);
  179. VOID amiga_sleep(unsigned int seconds);
  180. char *amiga_crypt(char *key, char *salt);
  181. char *amiga_getpass(char *prompt);
  182. int amiga_setgid(gid_t id);
  183. int amiga_setgroups(int ngroups, gid_t *groups);
  184. gid_t amiga_getgid(VOID);
  185. struct group *amiga_getgrgid(gid_t gid);
  186. struct group *amiga_getgrnam(char *name);
  187. int amiga_getgroups(int ngroups, gid_t *groups);
  188. struct hostent *amiga_gethostbyaddr(char *addr, int len, int type);
  189. struct hostent *amiga_gethostbyname(char *name);
  190. struct netent *amiga_getnetbyname(char *name);
  191. int amiga_gethostname(char *hostname, int size);
  192. struct passwd *amiga_getpwnam(char *name);
  193. struct passwd *amiga_getpwuid(uid_t uid);
  194. uid_t amiga_getuid(VOID);
  195. gid_t amiga_getegid(VOID);
  196. uid_t amiga_geteuid(VOID);
  197. int amiga_initgroups(char *name, gid_t basegroup);
  198. int amiga_setuid(uid_t id);
  199. int amiga_umask(int mask);
  200. unsigned long amiga_inet_addr(char *addr);
  201. char *amiga_inet_ntoa(struct in_addr in);
  202. int amiga_getopt(int argc, char *argv[], char *opts);
  203. int amiga_system(char *cmd);
  204. int amiga_fork(VOID);
  205. VOID __tzset(VOID);
  206. time_t time(time_t *timeptr);
  207. struct tm *gmtime(const time_t *t);
  208. struct tm *localtime(const time_t *t);
  209. int amiga_strcasecmp(char *a, char *b);
  210. int amiga_strncasecmp(char *a, char *b, int len);
  211. VOID (*amiga_signal(int which,VOID (* action)(int)))(int);
  212. VOID amiga_alarm(int seconds);
  213. int amiga_waitpid(pid_t pid, int *status, int options);
  214. long amiga_setsid(VOID);
  215. int amiga_setreuid(uid_t real, uid_t eff);
  216. int amiga_setregid(gid_t real, gid_t eff);
  217. int amiga_fcntl(int fd, int cmd, unsigned long arg);
  218. int amiga_getsockname(int sockfd, struct sockaddr *name, int *namelen);
  219. int amiga_statfs(char *name, struct statfs *f);
  220. int amiga_execl(char *path, char *arg, ...);
  221. char *amiga_strerror(int error);
  222. int amiga_access(char *name, int modes);
  223. off_t amiga_lseek(int fd, off_t offset, int mode);
  224. int amiga_chroot(char *name);
  225. int amiga_kill(pid_t pid, int sig);
  226. pid_t amiga_getpid(VOID);
  227. int amiga_fgetc(FILE *in);
  228. char *amiga_fgets(char *str, int n, FILE *in);
  229. int amiga_fputs(const char *str, FILE *out);
  230. int amiga_puts(const char *str);
  231. int amiga_vfprintf(FILE *out, const char *fmt, va_list args);
  232. int amiga_fprintf(FILE *out, const char *fmt, ...);
  233. int amiga_printf(const char *fmt, ...);
  234. size_t amiga_fwrite(const void *data, size_t blockSize, size_t numBlocks, FILE *out);
  235. size_t amiga_fread(void *data, size_t blockSize, size_t numBlocks, FILE *in);
  236. int amiga_fclose(FILE *stream);
  237. int amiga_fflush(FILE *stream);
  238. int amiga_fseek(FILE *stream, long int offset, int mode);
  239. long int amiga_ftell(FILE *stream);
  240. int amiga_setvbuf(FILE *fp, char *buff, int type, size_t size);
  241. int amiga_fputc(int c,FILE *stream);
  242. VOID amiga_setbuf(FILE *stream,char *buffer);
  243.  
  244. /******************************************************************************/
  245.  
  246. VOID __regargs __chkabort(VOID);
  247. VOID _CXOVF(VOID);
  248. VOID __regargs _CXBRK(VOID);
  249.  
  250. /******************************************************************************/
  251.  
  252. /* These are in the Samba runtime library. */
  253. extern int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
  254. extern int snprintf (char *str, size_t count, const char *fmt, ...);
  255.  
  256. /******************************************************************************/
  257.  
  258. #define ZERO    ((BPTR)0L)
  259. #define ERROR    (-1)
  260. #define OK        (0)
  261. #define SAME    (0)
  262. #define NO        !
  263. #define NOT        !
  264. #define DONT    !
  265. #define CANNOT    !
  266. #define BUSY    (NULL)
  267. #define NO_FLAG    (0)
  268.  
  269. /******************************************************************************/
  270.  
  271. #define FLAG_IS_SET(v,f)    (((v) & (f)) == (f))
  272. #define FLAG_IS_CLEAR(v,f)    (((v) & (f)) == 0)
  273.  
  274. #define SET_FLAG(v,f)        (v |=  (f))
  275. #define CLEAR_FLAG(v,f)        (v &= ~(f))
  276.  
  277. /******************************************************************************/
  278.  
  279. #define STRING_IS_EMPTY(s)    (s[0] == '\0')
  280. #define NUM_ENTRIES(t)        (sizeof(t) / sizeof(t[0]))
  281.  
  282. /******************************************************************************/
  283.  
  284. #define FIB_IS_FILE(fib)    ((fib)->fib_DirEntryType < 0)
  285. #define FIB_IS_DRAWER(fib)    ((fib)->fib_DirEntryType >= 0 && (fib)->fib_DirEntryType != ST_SOFTLINK)
  286.  
  287. /******************************************************************************/
  288.  
  289. #define UFB_IS_SOCKET        0x0800
  290. #define UFB_IS_NON_BLOCKING    0x1000
  291. #define UFB_UNLINK            0x2000
  292. #define UFB_LOCKED            0x4000
  293.  
  294. #define UNIX_TIME_OFFSET    252482400
  295.  
  296. #define MAX_BSTR_LEN        256
  297. #define MAX_FILENAME_LEN    512
  298. #define MAX_FFS_NAME_LEN    30
  299.  
  300. /******************************************************************************/
  301.  
  302. long __oslibversion = 37;
  303.  
  304. /******************************************************************************/
  305.  
  306. extern struct Library * SysBase;
  307. extern struct Library * DOSBase;
  308. extern struct Library * UtilityBase;
  309.  
  310. /******************************************************************************/
  311.  
  312. STATIC struct Device * TimerBase;
  313. STATIC struct MsgPort * TimerPort;
  314. STATIC struct timerequest * TimerRequest;
  315. STATIC LONG MinutesWest;
  316.  
  317. /******************************************************************************/
  318.  
  319. STATIC struct Library * SocketBase;
  320. STATIC struct Library * UserGroupBase;
  321.  
  322. /******************************************************************************/
  323.  
  324. #if defined(_M68020) && defined(_M68881)
  325. #define MACHINE_TYPE "['020+FPU]"
  326. #elif defined(_M68020)
  327. #define MACHINE_TYPE "['020]"
  328. #else
  329. #define MACHINE_TYPE "[68k]"
  330. #endif
  331.  
  332. /******************************************************************************/
  333.  
  334. #include "Amiga_Samba_rev.h"
  335. char * VersionTag = VERSTAG " " MACHINE_TYPE " Samba version 2.0.0 ported by Olaf `Olsen' Barthel <olsen@sourcery.han.de>";
  336.  
  337. /******************************************************************************/
  338.  
  339. /* This is for backwards compatibility with Kickstart 2.04 and
  340.  * avoids a deadlock when trying to get a shared lock on
  341.  * a semaphore already held in exclusive mode by the same Task.
  342.  */
  343. STATIC VOID
  344. SafeObtainSemaphoreShared(struct SignalSemaphore * semaphore)
  345. {
  346.     /* Do it right with Kickstart 3.x. */
  347.     if(SysBase->lib_Version >= 39)
  348.     {
  349.         ObtainSemaphoreShared(semaphore);
  350.     }
  351.     else
  352.     {
  353.         /* Try to get the shared semaphore */
  354.         if(CANNOT AttemptSemaphoreShared(semaphore))
  355.         {
  356.             /* Check if we can get the exclusive version */
  357.             if(CANNOT AttemptSemaphore(semaphore))
  358.             {
  359.                 /* Oh well, wait for the shared lock */
  360.                 ObtainSemaphoreShared(semaphore);
  361.             }
  362.         }
  363.     }
  364. }
  365.  
  366. /******************************************************************************/
  367.  
  368. STATIC BOOL AllowBreak = TRUE;
  369.  
  370. STATIC BOOL
  371. CheckAbort(VOID)
  372. {
  373.     BOOL result;
  374.  
  375.     result = (BOOL)(AllowBreak && FLAG_IS_SET(SetSignal(0,SIGBREAKF_CTRL_C),SIGBREAKF_CTRL_C));
  376.  
  377.     return(result);
  378. }
  379.  
  380. VOID __regargs
  381. __chkabort(VOID)
  382. {
  383.     if(CheckAbort())
  384.         raise(SIGINT);
  385. }
  386.  
  387. int
  388. amiga_sigmask(int signum)
  389. {
  390.     int result = 0;
  391.  
  392.     ENTER();
  393.  
  394.     SHOWVALUE(signum);
  395.  
  396.     if(signum == SIGTERM || signum == SIGINT)
  397.         result = (1<<SIGINT);
  398.  
  399.     RETURN(result);
  400.     return(result);
  401. }
  402.  
  403. int
  404. amiga_sigblock(int sigmask)
  405. {
  406.     BOOL oldAllowBreak = AllowBreak;
  407.     int result = 0;
  408.  
  409.     ENTER();
  410.  
  411.     SHOWVALUE(sigmask);
  412.  
  413.     if(DONT AllowBreak)
  414.         result = (1<<SIGINT);
  415.  
  416.     if(FLAG_IS_SET(sigmask,(1<<SIGINT)))
  417.     {
  418.         AllowBreak = FALSE;
  419.  
  420.         if(oldAllowBreak != AllowBreak)
  421.         {
  422.             SocketBaseTags(
  423.                 SBTM_SETVAL(SBTC_BREAKMASK),NO_FLAG,
  424.             TAG_END);
  425.         }
  426.     }
  427.  
  428.     RETURN(result);
  429.     return(result);
  430. }
  431.  
  432. int
  433. amiga_sigsetmask(int sigmask)
  434. {
  435.     BOOL oldAllowBreak = AllowBreak;
  436.     int result = 0;
  437.  
  438.     ENTER();
  439.  
  440.     SHOWVALUE(sigmask);
  441.  
  442.     AllowBreak = FLAG_IS_CLEAR(sigmask,(1<<SIGINT));
  443.     if(oldAllowBreak != AllowBreak)
  444.     {
  445.         ULONG mask;
  446.  
  447.         if(AllowBreak)
  448.             mask = SIGBREAKF_CTRL_C;
  449.         else
  450.             mask = NO_FLAG;
  451.  
  452.         SocketBaseTags(
  453.             SBTM_SETVAL(SBTC_BREAKMASK),mask,
  454.         TAG_END);
  455.     }
  456.  
  457.     RETURN(result);
  458.     return(result);
  459. }
  460.  
  461. /******************************************************************************/
  462.  
  463. STATIC VOID
  464. ReportProblem(const char *fmt,...)
  465. {
  466.     extern const STRPTR _ProgramName;
  467.     BOOL useRequester = TRUE;
  468.     va_list varArgs;
  469.  
  470.     ASSERT(fmt != NULL);
  471.  
  472.     va_start(varArgs,fmt);
  473.  
  474.     /* Launched from Workbench? */
  475.     if(WBenchMsg == NULL)
  476.     {
  477.         if(DOSBase->lib_Version >= 37)
  478.         {
  479.             BPTR stream;
  480.  
  481.             /* Make a copy of the current terminal
  482.              * output stream. This avoids sending
  483.              * an error message through a redirected
  484.              * standard output stream, the output
  485.              * will go straight to the terminal.
  486.              */
  487.             stream = Open("CONSOLE:",MODE_NEWFILE);
  488.             if(stream != ZERO)
  489.             {
  490.                 struct FileHandle * fh = BADDR(stream);
  491.  
  492.                 /* Check if the output was redirected
  493.                  * to "NIL:"; if not, print the error
  494.                  * error message.
  495.                  */
  496.                 if(fh->fh_Type != NULL)
  497.                 {
  498.                     FPrintf(stream,"%s: ",_ProgramName);
  499.                     VFPrintf(stream,(STRPTR)fmt,(APTR)varArgs);
  500.                     FPrintf(stream,"\a\n");
  501.  
  502.                     useRequester = FALSE;
  503.                 }
  504.  
  505.                 Close(stream);
  506.             }
  507.         }
  508.     }
  509.  
  510.     /* Oh well, don't use the Shell for output. Put up a
  511.      * requester.
  512.      */
  513.     if(useRequester)
  514.     {
  515.         struct Library * IntuitionBase;
  516.  
  517.         IntuitionBase = OpenLibrary("intuition.library",37);
  518.         if(IntuitionBase != NULL)
  519.         {
  520.             struct Window * reqWindow;
  521.             struct EasyStruct es;
  522.             char title[100];
  523.  
  524.             snprintf(title,sizeof(title)-1,"Amiga Samba Error (%s)",FilePart(_ProgramName));
  525.             title[sizeof(title)-1] = '\0';
  526.  
  527.             memset(&es,0,sizeof(es));
  528.  
  529.             es.es_StructSize    = sizeof(es);
  530.             es.es_Title            = (STRPTR)title;
  531.             es.es_TextFormat    = (STRPTR)fmt;
  532.             es.es_GadgetFormat    = "Ok";
  533.  
  534.             reqWindow = BuildEasyRequestArgs(NULL,&es,0,(APTR)varArgs);
  535.             if(reqWindow != NULL)
  536.             {
  537.                 struct timerequest * timeRequest = NULL;
  538.                 struct MsgPort * timePort;
  539.                 BOOL timerOpen = FALSE;
  540.                 ULONG windowSignal;
  541.                 ULONG timerSignal;
  542.                 ULONG signals;
  543.                 BOOL done;
  544.  
  545.                 timePort = CreateMsgPort();
  546.                 if(timePort != NULL)
  547.                 {
  548.                     timeRequest = CreateIORequest(timePort,sizeof(*timeRequest));
  549.                     if(timeRequest != NULL)
  550.                     {
  551.                         if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)timeRequest,0) == OK)
  552.                             timerOpen = TRUE;
  553.                     }
  554.                 }
  555.  
  556.                 windowSignal = (1UL << reqWindow->UserPort->mp_SigBit);
  557.  
  558.                 if(timerOpen)
  559.                 {
  560.                     timerSignal = (1UL << timePort->mp_SigBit);
  561.  
  562.                     timeRequest->tr_node.io_Command    = TR_ADDREQUEST;
  563.                     timeRequest->tr_time.tv_secs    = 30;
  564.                     timeRequest->tr_time.tv_micro    = 0;
  565.  
  566.                     SendIO((struct IORequest *)timeRequest);
  567.                 }
  568.                 else
  569.                 {
  570.                     timerSignal = 0;
  571.                 }
  572.  
  573.                 DisplayBeep(reqWindow->WScreen);
  574.  
  575.                 done = FALSE;
  576.                 do
  577.                 {
  578.                     signals = Wait(windowSignal | timerSignal);
  579.  
  580.                     if(FLAG_IS_SET(signals,windowSignal))
  581.                     {
  582.                         if(SysReqHandler(reqWindow,NULL,FALSE) >= 0)
  583.                             done = TRUE;
  584.                     }
  585.  
  586.                     if(FLAG_IS_SET(signals,timerSignal))
  587.                     {
  588.                         done = TRUE;
  589.                     }
  590.                 }
  591.                 while(NOT done);
  592.  
  593.                 if(timerOpen)
  594.                 {
  595.                     if(CheckIO((struct IORequest *)timeRequest) == BUSY)
  596.                         AbortIO((struct IORequest *)timeRequest);
  597.  
  598.                     WaitIO((struct IORequest *)timeRequest);
  599.  
  600.                     CloseDevice((struct IORequest *)timeRequest);
  601.                 }
  602.  
  603.                 DeleteIORequest((struct IORequest *)timeRequest);
  604.                 DeleteMsgPort(timePort);
  605.  
  606.                 FreeSysRequest(reqWindow);
  607.             }
  608.  
  609.             CloseLibrary(IntuitionBase);
  610.         }
  611.     }
  612.  
  613.     va_end(varArgs);
  614. }
  615.  
  616. /******************************************************************************/
  617.  
  618. STATIC APTR OldWindowPtr;
  619. STATIC LONG ForbidCount;
  620.  
  621. STATIC VOID
  622. ForbidDOSCleanup(VOID)
  623. {
  624.     if(ForbidCount > 0)
  625.     {
  626.         struct Process * pr = (struct Process *)FindTask(NULL);
  627.  
  628.         pr->pr_WindowPtr = OldWindowPtr;
  629.  
  630.         ForbidCount = 0;
  631.     }
  632. }
  633.  
  634. STATIC VOID
  635. PermitDOS(VOID)
  636. {
  637.     ASSERT(ForbidCount > 0);
  638.  
  639.     if(--ForbidCount == 0)
  640.     {
  641.         struct Process * pr = (struct Process *)FindTask(NULL);
  642.  
  643.         pr->pr_WindowPtr = OldWindowPtr;
  644.     }
  645. }
  646.  
  647. STATIC VOID
  648. ForbidDOS(VOID)
  649. {
  650.     if(ForbidCount++ == 0)
  651.     {
  652.         struct Process * pr = (struct Process *)FindTask(NULL);
  653.  
  654.         OldWindowPtr = pr->pr_WindowPtr;
  655.         pr->pr_WindowPtr = (APTR)-1;
  656.     }
  657. }
  658.  
  659. /******************************************************************************/
  660.  
  661. #define SINGLE_CHARACTER_MODE    (1)
  662. #define BUFFERED_MODE            (0)
  663.  
  664. STATIC int MaxNonblockingDescriptor = -1;
  665.  
  666. STATIC VOID
  667. UnblockDescriptorCleanup(VOID)
  668. {
  669.     struct UFB * ufb;
  670.     int fd;
  671.  
  672.     /* We look for descriptors we switched into
  673.      * non-blocking mode and reset them back
  674.      * to blocking mode.
  675.      */
  676.     for(fd = 0 ; fd <= MaxNonblockingDescriptor ; fd++)
  677.     {
  678.         ufb = chkufb(fd);
  679.         if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_NON_BLOCKING))
  680.         {
  681.             SetMode((BPTR)ufb->ufbfh,BUFFERED_MODE);
  682.  
  683.             CLEAR_FLAG(ufb->ufbflg,UFB_IS_NON_BLOCKING);
  684.         }
  685.     }
  686. }
  687.  
  688. STATIC BOOL
  689. IsDescriptorNonblocking(int fd)
  690. {
  691.     struct UFB * ufb;
  692.     BOOL result = FALSE;
  693.  
  694.     /* Verify if a descriptor was switched into non-blocking mode. */
  695.     ufb = chkufb(fd);
  696.     if(ufb != NULL)
  697.         result = FLAG_IS_SET(ufb->ufbflg,UFB_IS_NON_BLOCKING);
  698.  
  699.     return(result);
  700. }
  701.  
  702. STATIC VOID
  703. BlockDescriptor(int fd)
  704. {
  705.     struct UFB * ufb;
  706.  
  707.     /* This resets a file descriptor to blocking mode,
  708.      * once it has been set to blocking mode.
  709.      */
  710.     ufb = chkufb(fd);
  711.     if(ufb != NULL)
  712.     {
  713.         if(FLAG_IS_SET(ufb->ufbflg,UFB_IS_NON_BLOCKING))
  714.         {
  715.             SetMode((BPTR)ufb->ufbfh,BUFFERED_MODE);
  716.  
  717.             CLEAR_FLAG(ufb->ufbflg,UFB_IS_NON_BLOCKING);
  718.         }
  719.     }
  720. }
  721.  
  722. STATIC VOID
  723. UnblockDescriptor(int fd)
  724. {
  725.     struct UFB * ufb;
  726.  
  727.     ufb = chkufb(fd);
  728.     if(ufb != NULL)
  729.     {
  730.         /* Make sure we got a file and it's not already
  731.          * in non-blocking mode.
  732.          */
  733.         if(FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_SOCKET) && FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_NON_BLOCKING))
  734.         {
  735.             /* Try to flip it into single character mode,
  736.              * which we treat as "non-blocking" mode.
  737.              */
  738.             if(SetMode((BPTR)ufb->ufbfh,SINGLE_CHARACTER_MODE))
  739.             {
  740.                 SET_FLAG(ufb->ufbflg,UFB_IS_NON_BLOCKING);
  741.  
  742.                 /* Remember which one we switched. */
  743.                 if(MaxNonblockingDescriptor < fd)
  744.                     MaxNonblockingDescriptor = fd;
  745.             }
  746.         }
  747.     }
  748. }
  749.  
  750. /******************************************************************************/
  751.  
  752. struct SavedDescriptorNode
  753. {
  754.     struct MinNode    sdn_MinNode;
  755.     struct UFB *    sdn_UFB;
  756.     BPTR            sdn_FileHandle;
  757. };
  758.  
  759. STATIC BOOL DescriptorListInitialized = FALSE;
  760. STATIC struct List DescriptorList;
  761.  
  762. STATIC VOID
  763. SaveDescriptorCleanup(VOID)
  764. {
  765.     /* This routine restores all file descriptors
  766.      * we used to map to sockets to use proper file
  767.      * handles.
  768.      */
  769.     if(DescriptorListInitialized)
  770.     {
  771.         struct SavedDescriptorNode * sdn;
  772.  
  773.         for(sdn = (struct SavedDescriptorNode *)DescriptorList.lh_Head ;
  774.             sdn->sdn_MinNode.mln_Succ != NULL ;
  775.             sdn = (struct SavedDescriptorNode *)sdn->sdn_MinNode.mln_Succ)
  776.         {
  777.             /* Make sure that if this file is bound to
  778.              * a socket, the socket is closed.
  779.              */
  780.             if(FLAG_IS_SET(sdn->sdn_UFB->ufbflg,UFB_IS_SOCKET))
  781.             {
  782.                 CloseSocket(sdn->sdn_UFB->ufbfh);
  783.  
  784.                 CLEAR_FLAG(sdn->sdn_UFB->ufbflg,UFB_IS_SOCKET);
  785.             }
  786.  
  787.             sdn->sdn_UFB->ufbfh = sdn->sdn_FileHandle;
  788.         }
  789.     }
  790. }
  791.  
  792. STATIC VOID
  793. RestoreDescriptor(struct UFB * ufb)
  794. {
  795.     ASSERT(ufb != NULL);
  796.  
  797.     /* This routine restores one particular file descriptor
  798.      * which was used as a socket to refer to a proper
  799.      * file handle.
  800.      */
  801.     if(DescriptorListInitialized)
  802.     {
  803.         struct SavedDescriptorNode * sdn;
  804.  
  805.         for(sdn = (struct SavedDescriptorNode *)DescriptorList.lh_Head ;
  806.             sdn->sdn_MinNode.mln_Succ != NULL ;
  807.             sdn = (struct SavedDescriptorNode *)sdn->sdn_MinNode.mln_Succ)
  808.         {
  809.             if(sdn->sdn_UFB == ufb)
  810.             {
  811.                 sdn->sdn_UFB->ufbfh = sdn->sdn_FileHandle;
  812.  
  813.                 Remove((struct Node *)sdn);
  814.                 free(sdn);
  815.  
  816.                 break;
  817.             }
  818.         }
  819.     }
  820. }
  821.  
  822. STATIC BOOL
  823. SaveDescriptor(struct UFB * ufb)
  824. {
  825.     struct SavedDescriptorNode * sdn;
  826.     BOOL result = FALSE;
  827.  
  828.     ASSERT(ufb != NULL);
  829.  
  830.     /* Set up the descriptor list, unless it's already
  831.      * initialized.
  832.      */
  833.     if(NOT DescriptorListInitialized)
  834.     {
  835.         NewList(&DescriptorList);
  836.         DescriptorListInitialized = TRUE;
  837.     }
  838.  
  839.     sdn = malloc(sizeof(*sdn));
  840.     if(sdn != NULL)
  841.     {
  842.         memset(sdn,0,sizeof(*sdn));
  843.  
  844.         /* Remember the file buffer and the file
  845.          * handle attached to the descriptor.
  846.          */
  847.         sdn->sdn_UFB        = ufb;
  848.         sdn->sdn_FileHandle    = ufb->ufbfh;
  849.  
  850.         AddHead(&DescriptorList,(struct Node *)sdn);
  851.  
  852.         result = TRUE;
  853.     }
  854.  
  855.     return(result);
  856. }
  857.  
  858. /******************************************************************************/
  859.  
  860. STATIC BOOL InitialCurrentDirInitialized = FALSE;
  861. STATIC BPTR InitialCurrentDir;
  862. STATIC BPTR ChangedCurrentDir;
  863.  
  864. CBMLIB_DESTRUCTOR(CloseLibsAndDevs)
  865. {
  866.     ENTER();
  867.  
  868.     /* Return to the directory we were in
  869.      * when we started.
  870.      */
  871.     if(InitialCurrentDirInitialized)
  872.     {
  873.         CurrentDir(InitialCurrentDir);
  874.         InitialCurrentDirInitialized = FALSE;
  875.     }
  876.  
  877.     /* If the current directory was changed, unlock it. */
  878.     if(ChangedCurrentDir != ZERO)
  879.     {
  880.         UnLock(ChangedCurrentDir);
  881.         ChangedCurrentDir = ZERO;
  882.     }
  883.  
  884.     CleanupSambaSemaphore();
  885.  
  886.     if(TimerRequest != NULL)
  887.     {
  888.         if(TimerRequest->tr_node.io_Device != NULL)
  889.             CloseDevice((struct IORequest *)TimerRequest);
  890.  
  891.         DeleteIORequest((struct IORequest *)TimerRequest);
  892.         TimerRequest = NULL;
  893.     }
  894.  
  895.     if(TimerPort != NULL)
  896.     {
  897.         DeleteMsgPort(TimerPort);
  898.         TimerPort = NULL;
  899.     }
  900.  
  901.     TimerBase = NULL;
  902.  
  903.     if(SocketBase != NULL)
  904.     {
  905.         CloseLibrary(SocketBase);
  906.         SocketBase = NULL;
  907.     }
  908.  
  909.     if(UserGroupBase != NULL)
  910.     {
  911.         CloseLibrary(UserGroupBase);
  912.         UserGroupBase = NULL;
  913.     }
  914.  
  915.     LEAVE();
  916. }
  917.  
  918. CBMLIB_CONSTRUCTOR(OpenLibsAndDevs)
  919. {
  920.     extern STRPTR _ProgramName;
  921.     BOOL sambaSemaphoreCreated;
  922.     struct LocaleBase * LocaleBase;
  923.     char *timerError = "";
  924.     BPTR sambaLock;
  925.     int result = ERROR;
  926.  
  927.     SETPROGRAMNAME(_ProgramName);
  928.     SETDEBUGLEVEL(0);
  929.  
  930.     ENTER();
  931.  
  932.     SocketBase = OpenLibrary("bsdsocket.library",4);
  933.     UserGroupBase = OpenLibrary("usergroup.library",1);
  934.  
  935.     if(SysBase->lib_Version >= 37)
  936.     {
  937.         TimerPort = CreateMsgPort();
  938.         if(TimerPort != NULL)
  939.         {
  940.             TimerRequest = (struct timerequest *)CreateIORequest(TimerPort,sizeof(*TimerRequest));
  941.             if(TimerRequest != NULL)
  942.             {
  943.                 if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)TimerRequest,NULL) == OK)
  944.                     TimerBase = TimerRequest->tr_node.io_Device;
  945.                 else
  946.                     timerError = "opening \"timer.device\"";
  947.             }
  948.             else
  949.             {
  950.                 timerError = "creating timer I/O request";
  951.             }
  952.         }
  953.         else
  954.         {
  955.             timerError = "creating timer message port";
  956.         }
  957.     }
  958.  
  959.     /* Try to determine this machine's time zone. */
  960.     LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38);
  961.     if(LocaleBase != NULL)
  962.     {
  963.         struct Locale * locale;
  964.  
  965.         locale = OpenLocale(NULL);
  966.         MinutesWest = locale->loc_GMTOffset;
  967.         CloseLocale(locale);
  968.  
  969.         CloseLibrary((struct Library *)LocaleBase);
  970.     }
  971.  
  972.     ForbidDOS();
  973.  
  974.     /* Try to get a lock on the "Samba:" directory,
  975.      * just to make sure the assignment is in place.
  976.      */
  977.     sambaLock = Lock("Samba:",SHARED_LOCK);
  978.     if(sambaLock != ZERO)
  979.         UnLock(sambaLock);
  980.  
  981.     PermitDOS();
  982.  
  983.     /* Initialize the global process ID database. */
  984.     sambaSemaphoreCreated = SetupSambaSemaphore();
  985.  
  986.     if(SocketBase != NULL && UserGroupBase != NULL && TimerBase != NULL &&
  987.        sambaLock != ZERO && sambaSemaphoreCreated)
  988.     {
  989.         STATIC long h_errno = 0;
  990.         struct timeval now;
  991.         int error;
  992.  
  993.         error = SocketBaseTags(
  994.             SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))),    &errno,
  995.             SBTM_SETVAL(SBTC_HERRNOLONGPTR),            &h_errno,
  996.             SBTM_SETVAL(SBTC_LOGTAGPTR),                _ProgramName,
  997.             SBTM_SETVAL(SBTC_BREAKMASK),                SIGBREAKF_CTRL_C,
  998.         TAG_END);
  999.         if(error != OK)
  1000.         {
  1001.             ReportProblem("Error initializing socket data (error=%ld).",error);
  1002.             goto out;
  1003.         }
  1004.  
  1005.         error = ug_SetupContextTags(_ProgramName,
  1006.             UGT_ERRNOPTR(sizeof(errno)),&errno,
  1007.         TAG_END);
  1008.         if(error != OK)
  1009.         {
  1010.             ReportProblem("Error initializing user group data (error=%ld).",error);
  1011.             goto out;
  1012.         }
  1013.  
  1014.         /* Use a new random number seed. */
  1015.         GetSysTime((APTR)&now);
  1016.         srand(now.tv_secs);
  1017.     }
  1018.     else
  1019.     {
  1020.         if(SocketBase == NULL)
  1021.             ReportProblem("Error opening \"bsdsocket.library\" V4.");
  1022.         else if (UserGroupBase == NULL)
  1023.             ReportProblem("Error opening \"usergroup.library\" V1.");
  1024.         else if (TimerBase == NULL)
  1025.             ReportProblem("Error %s.",timerError);
  1026.         else if (sambaLock == ZERO)
  1027.             ReportProblem("Error finding \"Samba:\" assignment.");
  1028.         else if (NOT sambaSemaphoreCreated)
  1029.             ReportProblem("Error creating Samba semaphore.");
  1030.  
  1031.         goto out;
  1032.     }
  1033.  
  1034.     /* Initialize the current time zone variable. */
  1035.     __tzset();
  1036.  
  1037.     result = OK;
  1038.  
  1039. out:
  1040.  
  1041.     RETURN(result);
  1042.     return(result);
  1043. }
  1044.  
  1045. /******************************************************************************/
  1046.  
  1047. DESTRUCTOR_P(SocketExit,501)
  1048. {
  1049.     ENTER();
  1050.  
  1051.     SaveDescriptorCleanup();
  1052.     UnblockDescriptorCleanup();
  1053.     CloseUnlinkUnlockCleanup();
  1054.     ForbidDOSCleanup();
  1055.  
  1056.     LEAVE();
  1057. }
  1058.  
  1059. /******************************************************************************/
  1060.  
  1061. CONSTRUCTOR_P(DaemonInit,501)
  1062. {
  1063.     ENTER();
  1064.  
  1065.     DaemonInit();
  1066.  
  1067.     RETURN(0);
  1068.     return(0);
  1069. }
  1070.  
  1071. /******************************************************************************/
  1072.  
  1073. struct MangleInfo
  1074. {
  1075.     char    mi_Substitute[MAX_FILENAME_LEN];
  1076.     char *    mi_OldName;
  1077. };
  1078.  
  1079. STATIC VOID
  1080. UnmangleName(char ** namePtr,struct MangleInfo * mi)
  1081. {
  1082.     /* Reset the name pointer to its previous position. */
  1083.     (*namePtr) = mi->mi_OldName;
  1084. }
  1085.  
  1086. STATIC int
  1087. MangleName(char ** namePtr,struct MangleInfo * mi)
  1088. {
  1089.     char * name = (*namePtr);
  1090.     int result = ERROR;
  1091.  
  1092.     ENTER();
  1093.  
  1094.     if(TranslateRelativePath(&name,mi->mi_Substitute,sizeof(mi->mi_Substitute)) == OK)
  1095.     {
  1096.         char * replace = mi->mi_Substitute;
  1097.         int len,i;
  1098.  
  1099.         len = strlen(name);
  1100.  
  1101.         /* If there is one, strip the trailing slash. */
  1102.         if(len > 1 && name[len-1] == '/')
  1103.         {
  1104.             if(name != replace)
  1105.             {
  1106.                 strcpy(replace,name);
  1107.                 name = replace;
  1108.             }
  1109.  
  1110.             name[--len] = '\0';
  1111.         }
  1112.  
  1113.         if(strcmp(name,".") == SAME)
  1114.         {
  1115.             /* Convert to current directory. */
  1116.             name = "";
  1117.         }
  1118.         else if (strcmp(name,"..") == SAME)
  1119.         {
  1120.             /* Convert to parent directory. */
  1121.             name = "/";
  1122.         }
  1123.         else if (strncmp(name,"./",2) == SAME)
  1124.         {
  1125.             /* Retain just the name. */
  1126.             name += 2;
  1127.         }
  1128.         else if (strncmp(name,"../",3) == SAME)
  1129.         {
  1130.             /* Convert to parent directory. */
  1131.             name += 2;
  1132.         }
  1133.         else if (strncmp(name,"/",1) == SAME)
  1134.         {
  1135.             /* Ok, so this is an absolute path. We first
  1136.              * check for a few special cases, the first
  1137.              * being a reference to "/tmp".
  1138.              */
  1139.             if(Strnicmp(name,"/tmp",4) == SAME && (name[4] == '/' || name[4] == '\0'))
  1140.             {
  1141.                 if(name[4] == '/')
  1142.                 {
  1143.                     /* Convert "/tmp/foo" to "T:foo". */
  1144.                     strcpy(replace,"T:");
  1145.                     memmove(&replace[2],&name[5],strlen(&name[5])+1);
  1146.                 }
  1147.                 else
  1148.                 {
  1149.                     /* Convert "/tmp" to "T:". */
  1150.                     strcpy(replace,"T:");
  1151.                 }
  1152.  
  1153.                 name = replace;
  1154.             }
  1155.             else if(Strnicmp(name,"/dev/",5) == SAME)
  1156.             {
  1157.                 /* Except for "/dev/null" all references to
  1158.                  * files in "/dev" are redirected to nonexistant
  1159.                  * files. Note that this relies upon the fact
  1160.                  * that "NIL:" is not a true device.
  1161.                  */
  1162.                 if(Stricmp(name,"/dev/null") == SAME)
  1163.                     name = "NIL:";
  1164.                 else
  1165.                     name = "NIL:this_file_never_opens";
  1166.             }
  1167.             else
  1168.             {
  1169.                 int i,rest = 0,len = 0;
  1170.  
  1171.                 /* Find out how long the first component
  1172.                  * of the absolute path is.
  1173.                  */
  1174.                 for(i = 1 ; i <= strlen(name) ; i++)
  1175.                 {
  1176.                     if(name[i] == '/' || name[i] == '\0')
  1177.                     {
  1178.                         len = i-1;
  1179.  
  1180.                         /* Is there anything following
  1181.                          * the path name?
  1182.                          */
  1183.                         if(name[i] == '/')
  1184.                             rest = i+1;
  1185.  
  1186.                         break;
  1187.                     }
  1188.                 }
  1189.  
  1190.                 /* Copy the first component and
  1191.                  * attach a colon. "/foo" becomes
  1192.                  * "foo:" (without the trailing NUL
  1193.                  * byte, this will get attached
  1194.                  * later).
  1195.                  */
  1196.                 memmove(replace,&name[1],len);
  1197.                 replace[len++] = ':';
  1198.  
  1199.                 /* Now add the finishing touches. "/foo/bar" finally
  1200.                  * becomes "foo:bar" and "/foo" becomes "foo:" with the
  1201.                  * trailing NUL byte attached.
  1202.                  */
  1203.                 if(rest > 0)
  1204.                     memmove(&replace[len],&name[rest],strlen(&name[rest])+1);
  1205.                 else
  1206.                     replace[len] = '\0';
  1207.  
  1208.                 name = replace;
  1209.             }
  1210.         }
  1211.  
  1212.         /* Convert any "./" or "../" embedded in the name
  1213.          * if necessary.
  1214.          */
  1215.         for(i = 0 ; i < strlen(name) ; i++)
  1216.         {
  1217.             if(strncmp(&name[i],"./",2) == SAME ||
  1218.                strncmp(&name[i],"../",3) == SAME)
  1219.             {
  1220.                 char * from    = name;
  1221.                 char * to    = replace;
  1222.  
  1223.                 name = replace;
  1224.  
  1225.                 while((*from) != '\0')
  1226.                 {
  1227.                     if((*from) == '.')
  1228.                     {
  1229.                         if(from[1] == '/' || from[1] == '\0')
  1230.                         {
  1231.                             /* "."  -> "" (done)
  1232.                              * "./" -> "" (continue)
  1233.                              */
  1234.                             if(from[1] == '\0')
  1235.                                 break;
  1236.                             else
  1237.                                 from += 2;
  1238.                         }
  1239.                         else if (from[1] == '.' && (from[2] == '/' || from[2] == '\0'))
  1240.                         {
  1241.                             /* ".."  -> "/" (done)
  1242.                              * "../" -> "/" (continue)
  1243.                              */
  1244.                             (*to++) = '/';
  1245.  
  1246.                             if(from[2] == '\0')
  1247.                                 break;
  1248.                             else
  1249.                                 from += 3;
  1250.                         }
  1251.                         else
  1252.                         {
  1253.                             (*to++) = (*from++);
  1254.                         }
  1255.                     }
  1256.                     else
  1257.                     {
  1258.                         (*to++) = (*from++);
  1259.                     }
  1260.                 }
  1261.  
  1262.                 (*to) = '\0';
  1263.  
  1264.                 break;
  1265.             }
  1266.         }
  1267.  
  1268.         /* Reduce any "//" embedded in the name if
  1269.          * necessary.
  1270.          */
  1271.         for(i = 0 ; i < strlen(name)-1 ; i++)
  1272.         {
  1273.             if(name[i] == '/' && name[i+1] == '/')
  1274.             {
  1275.                 int position,len;
  1276.  
  1277.                 if(name != replace)
  1278.                 {
  1279.                     strcpy(replace,name);
  1280.                     name = replace;
  1281.                 }
  1282.  
  1283.                 len = strlen(name);
  1284.  
  1285.                 position = len - 1;
  1286.                 while(position > 1 && name[position] != ':')
  1287.                 {
  1288.                     /* "foo/bar//baz" -> "foo/baz" */
  1289.                     if(name[position] == '/' && name[position-1] == '/')
  1290.                     {
  1291.                         int componentLen;
  1292.  
  1293.                         /* Move in front of the name component preceding the "//". */
  1294.                         componentLen = 0;
  1295.                         for(i = position - 2 ; i > 0 && name[i] != ':' && name[i] != '/' ; i--)
  1296.                             componentLen++;
  1297.  
  1298.                         if(componentLen > 0)
  1299.                         {
  1300.                             memmove(&name[position - (componentLen + 1)],&name[position + 1],len - (position + 1));
  1301.  
  1302.                             len -= componentLen + 2;
  1303.                             name[len] = '\0';
  1304.  
  1305.                             position -= componentLen + 1;
  1306.                         }
  1307.                     }
  1308.  
  1309.                     position--;
  1310.                 }
  1311.  
  1312.                 break;
  1313.             }
  1314.         }
  1315.  
  1316.         D(("original name |%s|",(*namePtr)));
  1317.         D((" mangled name |%s|",name));
  1318.  
  1319.         /* Look for extra colon characters
  1320.          * embedded in the name (as in "foo:bar:baz"
  1321.          * or "foo/bar:baz") which really don't
  1322.          * belong here.
  1323.          */
  1324.         len = strlen(name);
  1325.         for(i = 0 ; i < len ; i++)
  1326.         {
  1327.             if(name[i] == ':' || name[i] == '/')
  1328.             {
  1329.                 int j;
  1330.  
  1331.                 for(j = i+1 ; j < len ; j++)
  1332.                 {
  1333.                     if(name[j] == ':')
  1334.                     {
  1335.                         errno = EINVAL; /* invalid name */
  1336.                         goto out;
  1337.                     }
  1338.                 }
  1339.  
  1340.                 break;
  1341.             }
  1342.         }
  1343.  
  1344.         /* Now check if the file name is longer than the
  1345.          * maximum supported by the ROM file system. This
  1346.          * is to avoid name space clashes.
  1347.          */
  1348.         if(strlen(FilePart((STRPTR)name)) > MAX_FFS_NAME_LEN)
  1349.         {
  1350.             LONG error = OK;
  1351.             BPTR fileLock;
  1352.  
  1353.             /* This is a tricky issue: the filing system we are talking
  1354.              * to may be able to handle more than 30 characters, but then
  1355.              * it may be not, it's impossible to tell. We adopt the following
  1356.              * strategy: we try to access the named file and compare its
  1357.              * name against the one reported by the file system. If the name
  1358.              * reported by the file system is shorter than the one provided,
  1359.              * but matches it otherwise, we will assume that trouble is underway
  1360.              * and back out backwards.
  1361.              */
  1362.  
  1363.             ForbidDOS();
  1364.  
  1365.             fileLock = Lock((STRPTR)name,SHARED_LOCK);
  1366.             if(fileLock != ZERO)
  1367.             {
  1368.                 struct FileInfoBlock __aligned fib;
  1369.  
  1370.                 if(Examine(fileLock,&fib))
  1371.                 {
  1372.                     int len;
  1373.  
  1374.                     /* Now check if the name reported by the
  1375.                      * filing system is shorter than the
  1376.                      * one we asked for, but matches otherwise.
  1377.                      */
  1378.                     len = strlen(fib.fib_FileName);
  1379.                     if(strlen((STRPTR)name) > len && Strnicmp((STRPTR)name,fib.fib_FileName,len) == SAME)
  1380.                     {
  1381.                         /* The name is too long to handle. */
  1382.                         error = ERROR_LINE_TOO_LONG;
  1383.                     }
  1384.                 }
  1385.                 else
  1386.                 {
  1387.                     error = IoErr();
  1388.                 }
  1389.  
  1390.                 UnLock(fileLock);
  1391.             }
  1392.             else
  1393.             {
  1394.                 error = IoErr();
  1395.             }
  1396.  
  1397.             PermitDOS();
  1398.  
  1399.             /* We don't complain if the file does
  1400.              * not exist, but if it is currently in
  1401.              * use, on a volume that's not currently
  1402.              * mounted, etc. we will complain.
  1403.              */
  1404.             if(error != OK && error != ERROR_OBJECT_NOT_FOUND)
  1405.             {
  1406.                 SetIoErr(error);
  1407.                 MapIoErrToErrno();
  1408.  
  1409.                 goto out;
  1410.             }
  1411.         }
  1412.  
  1413.         mi->mi_OldName = (*namePtr);
  1414.         (*namePtr) = name;
  1415.  
  1416.         result = OK;
  1417.     }
  1418.  
  1419. out:
  1420.  
  1421.     RETURN(result);
  1422.     return(result);
  1423. }
  1424.  
  1425. /******************************************************************************/
  1426.  
  1427. STATIC int MaxOpenDescriptor = -1;
  1428.  
  1429. STATIC VOID
  1430. CloseUnlinkUnlockCleanup(VOID)
  1431. {
  1432.     struct UFB * ufb;
  1433.     int fd;
  1434.  
  1435.     ForbidDOS();
  1436.  
  1437.     /* Don't let anybody stop us. */
  1438.     signal(SIGINT,SIG_IGN);
  1439.     signal(SIGTERM,SIG_IGN);
  1440.  
  1441.     /* We look for descriptors we marked for
  1442.      * deletion.
  1443.      */
  1444.     for(fd = 0 ; fd <= MaxOpenDescriptor ; fd++)
  1445.     {
  1446.         CleanupFileLocks(fd);
  1447.  
  1448.         ufb = chkufb(fd);
  1449.         if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_UNLINK))
  1450.         {
  1451.             char fileName[MAX_FILENAME_LEN];
  1452.             BOOL removeIt;
  1453.  
  1454.             removeIt = NameFromFH((BPTR)ufb->ufbfh,fileName,sizeof(fileName));
  1455.  
  1456.             CLEAR_FLAG(ufb->ufbflg,UFB_UNLINK);
  1457.  
  1458.             close(fd);
  1459.  
  1460.             if(removeIt)
  1461.                 DeleteFile(fileName);
  1462.         }
  1463.     }
  1464.  
  1465.     PermitDOS();
  1466. }
  1467.  
  1468. int
  1469. amiga_unlink(char *name)
  1470. {
  1471.     struct MangleInfo mi;
  1472.     BPTR fileLock;
  1473.     int result = ERROR;
  1474.  
  1475.     chkabort();
  1476.  
  1477.     ASSERT(name != NULL);
  1478.  
  1479.     ENTER();
  1480.     SHOWSTRING(name);
  1481.  
  1482.     if(MangleName(&name,&mi) == OK)
  1483.     {
  1484.         LONG error = OK;
  1485.  
  1486.         ForbidDOS();
  1487.  
  1488.         fileLock = Lock(name,SHARED_LOCK);
  1489.         if(fileLock != ZERO)
  1490.         {
  1491.             struct FileInfoBlock __aligned fib;
  1492.  
  1493.             if(Examine(fileLock,&fib))
  1494.             {
  1495.                 UnLock(fileLock);
  1496.                 fileLock = ZERO;
  1497.  
  1498.                 /* Make sure that we get to remove
  1499.                  * a file, as the name implies.
  1500.                  */
  1501.                 if(FIB_IS_FILE(&fib))
  1502.                 {
  1503.                     if(DeleteFile(name))
  1504.                         result = OK;
  1505.                     else
  1506.                         error = IoErr();
  1507.                 }
  1508.                 else
  1509.                 {
  1510.                     errno = EISDIR;
  1511.                 }
  1512.             }
  1513.             else
  1514.             {
  1515.                 error = IoErr();
  1516.             }
  1517.  
  1518.             UnLock(fileLock);
  1519.         }
  1520.         else
  1521.         {
  1522.             error = IoErr();
  1523.         }
  1524.  
  1525.         PermitDOS();
  1526.  
  1527.         /* Check if we couldn't delete the file in
  1528.          * question because there still is a file
  1529.          * handle attached to it. If we can find that
  1530.          * file, we will mark it for deletion lateron
  1531.          * when the file is closed.
  1532.          */
  1533.         if(result != OK && error == ERROR_OBJECT_IN_USE)
  1534.         {
  1535.             char parentDirName[MAX_FILENAME_LEN];
  1536.             BOOL foundParentDirName;
  1537.             BPTR fileParentDir;
  1538.             int i;
  1539.  
  1540.             ASSERT(strlen(name) < sizeof(parentDirName));
  1541.  
  1542.             strcpy(parentDirName,name);
  1543.             foundParentDirName = FALSE;
  1544.  
  1545.             for(i = strlen(parentDirName)-1 ; i >= 0 ; i--)
  1546.             {
  1547.                 if(parentDirName[i] == ':')
  1548.                 {
  1549.                     if(parentDirName[i+1] != '\0')
  1550.                     {
  1551.                         parentDirName[i+1] = '\0';
  1552.                         foundParentDirName = TRUE;
  1553.                     }
  1554.  
  1555.                     break;
  1556.                 }
  1557.                 else if (parentDirName[i] == '/')
  1558.                 {
  1559.                     parentDirName[i] = '\0';
  1560.                     foundParentDirName = TRUE;
  1561.                     break;
  1562.                 }
  1563.             }
  1564.  
  1565.             /* Did we find this file's parent directory name? */
  1566.             if(foundParentDirName)
  1567.             {
  1568.                 D(("locking |%s|",parentDirName));
  1569.  
  1570.                 /* Get a lock on the file's parent directory. */
  1571.                 fileParentDir = Lock(parentDirName,SHARED_LOCK);
  1572.                 if(fileParentDir != ZERO)
  1573.                 {
  1574.                     BPTR descriptorParentDir;
  1575.                     BOOL gotIt = FALSE;
  1576.                     struct UFB * ufb;
  1577.                     int fd;
  1578.  
  1579.                     for(fd = 0 ; fd <= MaxOpenDescriptor ; fd++)
  1580.                     {
  1581.                         ufb = chkufb(fd);
  1582.                         if(ufb != NULL && FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_SOCKET))
  1583.                         {
  1584.                             /* And also get a lock on the file
  1585.                              * descriptor's parent directory.
  1586.                              */
  1587.                             descriptorParentDir = ParentOfFH((BPTR)ufb->ufbfh);
  1588.                             if(descriptorParentDir != ZERO)
  1589.                             {
  1590.                                 /* Are the two pointing to the same drawer? */
  1591.                                 if(SameLock(fileParentDir,descriptorParentDir) == LOCK_SAME)
  1592.                                 {
  1593.                                     struct FileInfoBlock __aligned fib;
  1594.  
  1595.                                     if(ExamineFH((BPTR)ufb->ufbfh,&fib))
  1596.                                     {
  1597.                                         /* Check if the two share the same name. */
  1598.                                         if(Stricmp(fib.fib_FileName,FilePart(name)) == SAME)
  1599.                                         {
  1600.                                             /* Mark this file for deletion. */
  1601.                                             SET_FLAG(ufb->ufbflg,UFB_UNLINK);
  1602.  
  1603.                                             gotIt = TRUE;
  1604.                                             error = OK;
  1605.                                             result = OK;
  1606.                                         }
  1607.                                     }
  1608.                                     else
  1609.                                     {
  1610.                                         SHOWMSG("couldn't examine the descriptor");
  1611.                                     }
  1612.                                 }
  1613.                                 else
  1614.                                 {
  1615.                                     SHOWMSG("file and descriptor don't live in the same drawer");
  1616.                                 }
  1617.  
  1618.                                 UnLock(descriptorParentDir);
  1619.                             }
  1620.                             else
  1621.                             {
  1622.                                 SHOWMSG("the descriptor doesn't have a parent directory (huh?!?)");
  1623.                             }
  1624.                         }
  1625.  
  1626.                         if(gotIt)
  1627.                             break;
  1628.                     }
  1629.  
  1630.                     UnLock(fileParentDir);
  1631.                 }
  1632.                 else
  1633.                 {
  1634.                     D(("couldn't get a lock on |%s|",parentDirName));
  1635.                 }
  1636.             }
  1637.             else
  1638.             {
  1639.                 D(("didn't find parent dir name of |%s|",name));
  1640.             }
  1641.         }
  1642.  
  1643.         /* Take care of the AmigaDOS error
  1644.          * code, if there is any.
  1645.          */
  1646.         if(result != OK && error != OK)
  1647.         {
  1648.             SetIoErr(error);
  1649.             MapIoErrToErrno();
  1650.         }
  1651.  
  1652.         UnmangleName(&name,&mi);
  1653.     }
  1654.  
  1655.     RETURN(result);
  1656.     return(result);
  1657. }
  1658.  
  1659. int
  1660. amiga_open(char *name,int mode,int prot)
  1661. {
  1662.     struct MangleInfo mi;
  1663.     int result = ERROR;
  1664.  
  1665.     chkabort();
  1666.  
  1667.     ASSERT(name != NULL);
  1668.  
  1669.     ENTER();
  1670.     SHOWSTRING(name);
  1671.     SHOWVALUE(mode);
  1672.     SHOWVALUE(prot);
  1673.  
  1674.     if(MangleName(&name,&mi) == OK)
  1675.     {
  1676.         /* Clear the "no delay" flag since the SAS/C
  1677.          * runtime library does not support it.
  1678.          */
  1679.         CLEAR_FLAG(mode,O_NONBLOCK);
  1680.  
  1681.         ForbidDOS();
  1682.  
  1683.         result = open(name,mode,prot);
  1684.         if(result != ERROR && MaxOpenDescriptor < result)
  1685.             MaxOpenDescriptor = result;
  1686.  
  1687.         PermitDOS();
  1688.  
  1689.         UnmangleName(&name,&mi);
  1690.     }
  1691.  
  1692.     RETURN(result);
  1693.     return(result);
  1694. }
  1695.  
  1696. /******************************************************************************/
  1697.  
  1698. STATIC char CurrentDirName[MAX_FILENAME_LEN] = "";
  1699.  
  1700. int
  1701. amiga_chdir(char *path)
  1702. {
  1703.     BOOL isAbsolutePath;
  1704.     struct MangleInfo mi;
  1705.     int result = ERROR;
  1706.  
  1707.     chkabort();
  1708.  
  1709.     ASSERT(path != NULL);
  1710.  
  1711.     ENTER();
  1712.     SHOWSTRING(path);
  1713.  
  1714.     /* Is this an absolute path? */
  1715.     isAbsolutePath = (BOOL)(path[0] == '/');
  1716.  
  1717.     if(MangleName(&path,&mi) == OK)
  1718.     {
  1719.         BPTR drawerLock;
  1720.  
  1721.         D(("chdir(\"%s\")",path));
  1722.  
  1723.         ForbidDOS();
  1724.  
  1725.         drawerLock = Lock(path,SHARED_LOCK);
  1726.         if(drawerLock != ZERO)
  1727.         {
  1728.             struct FileInfoBlock __aligned fib;
  1729.  
  1730.             if(Examine(drawerLock,&fib))
  1731.             {
  1732.                 /* We can only move into drawers. */
  1733.                 if(FIB_IS_DRAWER(&fib))
  1734.                 {
  1735.                     /* If necessary, get the name of
  1736.                      * the drawer to move into.
  1737.                      */
  1738.                     if(NOT isAbsolutePath)
  1739.                     {
  1740.                         UBYTE localName[MAX_FILENAME_LEN];
  1741.  
  1742.                         if(NameFromLock(drawerLock,localName,sizeof(localName)))
  1743.                             result = MapFileNameAmigaToUnix(localName,CurrentDirName,sizeof(CurrentDirName));
  1744.                         else
  1745.                             MapIoErrToErrno();
  1746.                     }
  1747.                     else
  1748.                     {
  1749.                         result = OK;
  1750.                     }
  1751.  
  1752.                     /* If everything went well,
  1753.                      * move into the drawer.
  1754.                      */
  1755.                     if(result == OK)
  1756.                     {
  1757.                         BPTR oldDrawer;
  1758.  
  1759.                         oldDrawer = CurrentDir(drawerLock);
  1760.  
  1761.                         /* Unlock the old drawer we came from
  1762.                          * unless we want to return to it
  1763.                          * when the program exits.
  1764.                          */
  1765.                         if(InitialCurrentDirInitialized)
  1766.                         {
  1767.                             UnLock(oldDrawer);
  1768.                         }
  1769.                         else
  1770.                         {
  1771.                             InitialCurrentDir = oldDrawer;
  1772.                             InitialCurrentDirInitialized = TRUE;
  1773.                         }
  1774.  
  1775.                         /* Make sure that this drawer is going
  1776.                          * to be unlocked when the program exits.
  1777.                          */
  1778.                         ChangedCurrentDir = drawerLock;
  1779.                     }
  1780.                 }
  1781.                 else
  1782.                 {
  1783.                     errno = ENOTDIR;
  1784.                 }
  1785.             }
  1786.             else
  1787.             {
  1788.                 MapIoErrToErrno();
  1789.             }
  1790.  
  1791.             if(result != OK)
  1792.                 UnLock(drawerLock);
  1793.         }
  1794.         else
  1795.         {
  1796.             MapIoErrToErrno();
  1797.         }
  1798.  
  1799.         PermitDOS();
  1800.  
  1801.         UnmangleName(&path,&mi);
  1802.  
  1803.         if(result == OK && isAbsolutePath)
  1804.             strcpy(CurrentDirName,path);
  1805.     }
  1806.  
  1807.     RETURN(result);
  1808.     return(result);
  1809. }
  1810.  
  1811. /******************************************************************************/
  1812.  
  1813. struct OpenDirNode
  1814. {
  1815.     struct MinNode            odn_MinNode;
  1816.     BPTR                    odn_FileLock;
  1817.     struct FileInfoBlock    odn_FIB;
  1818.     struct List                odn_VolumeList;
  1819.     DIR                        odn_DIR;
  1820.     BOOL                    odn_ReadingVolumes;
  1821.     struct dirent            odn_DirectoryEntry;
  1822.     struct Node *            odn_NextNode;
  1823.     ULONG                    odn_NextDirEntryIndex;
  1824.     LONG                    odn_ParentDirKey;
  1825. };
  1826.  
  1827. STATIC struct List OpenDirList;
  1828. STATIC BOOL OpenDirListInitialized = FALSE;
  1829.  
  1830. STATIC ULONG RootBlocks = 0;
  1831. STATIC ULONG RootBlocksUsed = 0;
  1832.  
  1833. STATIC VOID
  1834. OpenDirCleanup(VOID)
  1835. {
  1836.     struct OpenDirNode * odn;
  1837.  
  1838.     /* Unlock all directories still being scanned
  1839.      * when exit() was called.
  1840.      */
  1841.     for(odn = (struct OpenDirNode *)OpenDirList.lh_Head ;
  1842.         odn->odn_MinNode.mln_Succ != NULL ;
  1843.         odn = (struct OpenDirNode *)odn->odn_MinNode.mln_Succ)
  1844.     {
  1845.         UnLock(odn->odn_FileLock);
  1846.     }
  1847. }
  1848.  
  1849. DIR *
  1850. amiga_opendir(char *dirName)
  1851. {
  1852.     char localDirName[MAX_FILENAME_LEN];
  1853.     DIR *result = NULL;
  1854.  
  1855.     chkabort();
  1856.  
  1857.     ASSERT(dirName != NULL);
  1858.  
  1859.     ENTER();
  1860.  
  1861.     SHOWSTRING(dirName);
  1862.  
  1863.     /* Make sure that the directory list is
  1864.      * set up properly.
  1865.      */
  1866.     if(NOT OpenDirListInitialized)
  1867.     {
  1868.         NewList(&OpenDirList);
  1869.         OpenDirListInitialized = TRUE;
  1870.         atexit(OpenDirCleanup);
  1871.     }
  1872.  
  1873.     if(TranslateRelativePath(&dirName,localDirName,sizeof(localDirName)) == OK)
  1874.     {
  1875.         /* Check if we are to scan the virtual root directory. */
  1876.         if(strcmp(dirName,"/") == SAME)
  1877.         {
  1878.             struct OpenDirNode * odn;
  1879.  
  1880.             odn = malloc(sizeof(*odn));
  1881.             if(odn != NULL)
  1882.             {
  1883.                 struct DosList * dol;
  1884.  
  1885.                 RootBlocks = RootBlocksUsed = 0;
  1886.  
  1887.                 memset(odn,0,sizeof(*odn));
  1888.                 odn->odn_ReadingVolumes = TRUE;
  1889.                 odn->odn_DIR.dd_buf = (char *)odn;
  1890.                 NewList(&odn->odn_VolumeList);
  1891.  
  1892.                 AddHead(&OpenDirList,(struct Node *)odn);
  1893.  
  1894.                 result = &odn->odn_DIR;
  1895.  
  1896.                 /* Now collect all volumes in the system. */
  1897.                 dol = NextDosEntry(LockDosList(LDF_VOLUMES|LDF_READ),
  1898.                                                LDF_VOLUMES|LDF_READ);
  1899.                 while(dol != NULL)
  1900.                 {
  1901.                     /* Does the volume refer to a medium that is right
  1902.                      * now present in the drive?
  1903.                      */
  1904.                     if(dol->dol_Task != NULL)
  1905.                     {
  1906.                         struct InfoData __aligned id;
  1907.  
  1908.                         /* Is there a disk present? */
  1909.                         if(DoPkt(dol->dol_Task,ACTION_DISK_INFO,MKBADDR(&id),    0,0,0,0))
  1910.                         {
  1911.                             STRPTR name = BADDR(dol->dol_Name);
  1912.                             struct Node * node;
  1913.  
  1914.                             /* Collect the number of blocks used and
  1915.                              * available in our fake root directory.
  1916.                              * Not that it matters much...
  1917.                              */
  1918.                             if(id.id_BytesPerBlock == 512)
  1919.                             {
  1920.                                 RootBlocks        += id.id_NumBlocks;
  1921.                                 RootBlocksUsed    += id.id_NumBlocksUsed;
  1922.                             }
  1923.                             else
  1924.                             {
  1925.                                 RootBlocks        += (id.id_NumBlocks * id.id_BytesPerBlock) / 512;
  1926.                                 RootBlocksUsed    += (id.id_NumBlocksUsed * id.id_BytesPerBlock) / 512;
  1927.                             }
  1928.  
  1929.                             node = malloc(sizeof(*node) + ((int)name[0])+1);
  1930.                             if(node != NULL)
  1931.                             {
  1932.                                 /* Copy the name of the volume. */
  1933.                                 node->ln_Name = (char *)(node + 1);
  1934.                                 strncpy(node->ln_Name,&name[1],name[0]);
  1935.                                 node->ln_Name[ name[0] ] = '\0';
  1936.  
  1937.                                 AddTail(&odn->odn_VolumeList,node);
  1938.  
  1939.                                 if(odn->odn_NextNode == NULL)
  1940.                                     odn->odn_NextNode = node;
  1941.                             }
  1942.                         }
  1943.                     }
  1944.  
  1945.                     dol = NextDosEntry(dol,LDF_VOLUMES|LDF_READ);
  1946.                 }
  1947.  
  1948.                 UnLockDosList(LDF_VOLUMES|LDF_READ);
  1949.             }
  1950.             else
  1951.             {
  1952.                 errno = ENOMEM;
  1953.             }
  1954.         }
  1955.         else
  1956.         {
  1957.             struct MangleInfo mi;
  1958.  
  1959.             if(MangleName(&dirName,&mi) == OK)
  1960.             {
  1961.                 BPTR fileLock;
  1962.  
  1963.                 ForbidDOS();
  1964.  
  1965.                 fileLock = Lock(dirName,SHARED_LOCK);
  1966.                 if(fileLock != ZERO)
  1967.                 {
  1968.                     struct OpenDirNode * odn;
  1969.  
  1970.                     odn = malloc(sizeof(*odn));
  1971.                     if(odn != NULL)
  1972.                     {
  1973.                         BPTR parentDir;
  1974.  
  1975.                         memset(odn,0,sizeof(*odn));
  1976.  
  1977.                         parentDir = ParentDir(fileLock);
  1978.                         if(parentDir != ZERO)
  1979.                         {
  1980.                             if(Examine(parentDir,&odn->odn_FIB))
  1981.                                 odn->odn_ParentDirKey = odn->odn_FIB.fib_DiskKey;
  1982.  
  1983.                             UnLock(parentDir);
  1984.                         }
  1985.  
  1986.                         if(Examine(fileLock,&odn->odn_FIB))
  1987.                         {
  1988.                             /* Make sure that we are
  1989.                              * trying to read a drawer
  1990.                              * and not a file.
  1991.                              */
  1992.                             if(FIB_IS_DRAWER(&odn->odn_FIB))
  1993.                             {
  1994.                                 odn->odn_DIR.dd_buf = (char *)odn;
  1995.                                 odn->odn_FileLock = fileLock;
  1996.                                 NewList(&odn->odn_VolumeList);
  1997.  
  1998.                                 /* The lock has been "swallowed"
  1999.                                  * by the dir node; make sure that
  2000.                                  * we don't unlock it.
  2001.                                  */
  2002.                                 fileLock = ZERO;
  2003.  
  2004.                                 AddHead(&OpenDirList,(struct Node *)odn);
  2005.                                 result = &odn->odn_DIR;
  2006.                             }
  2007.                             else
  2008.                             {
  2009.                                 errno = ENOTDIR;
  2010.                             }
  2011.                         }
  2012.                         else
  2013.                         {
  2014.                             MapIoErrToErrno();
  2015.                         }
  2016.  
  2017.                         if(result == NULL)
  2018.                             free(odn);
  2019.                     }
  2020.                     else
  2021.                     {
  2022.                         errno = ENOMEM;
  2023.                     }
  2024.  
  2025.                     UnLock(fileLock);
  2026.                 }
  2027.                 else
  2028.                 {
  2029.                     MapIoErrToErrno();
  2030.                 }
  2031.  
  2032.                 PermitDOS();
  2033.  
  2034.                 UnmangleName(&dirName,&mi);
  2035.             }
  2036.         }
  2037.     }
  2038.  
  2039.     RETURN(result);
  2040.     return(result);
  2041. }
  2042.  
  2043. VOID
  2044. amiga_closedir(DIR *dir)
  2045. {
  2046.     if(dir != NULL)
  2047.     {
  2048.         struct OpenDirNode * odn = (struct OpenDirNode *)dir->dd_buf;
  2049.  
  2050.         if(odn != NULL)
  2051.         {
  2052.             struct Node * node;
  2053.  
  2054.             Remove((struct Node *)odn);
  2055.  
  2056.             while((node = RemHead(&odn->odn_VolumeList)) != NULL)
  2057.                 free(node);
  2058.  
  2059.             UnLock(odn->odn_FileLock);
  2060.             free(odn);
  2061.         }
  2062.     }
  2063.  
  2064.     chkabort();
  2065. }
  2066.  
  2067. struct dirent *
  2068. amiga_readdir(DIR *dir)
  2069. {
  2070.     struct dirent * result = NULL;
  2071.  
  2072.     chkabort();
  2073.  
  2074.     if(dir != NULL)
  2075.     {
  2076.         struct OpenDirNode * odn = (struct OpenDirNode *)dir->dd_buf;
  2077.  
  2078.         if(odn != NULL)
  2079.         {
  2080.             struct dirent * d = &odn->odn_DirectoryEntry;
  2081.  
  2082.             if(odn->odn_ReadingVolumes)
  2083.             {
  2084.                 /* The first directory entry points
  2085.                  * back to the directory itself.
  2086.                  */
  2087.                 if(odn->odn_NextDirEntryIndex == 0)
  2088.                 {
  2089.                     strcpy(d->d_name,".");
  2090.  
  2091.                     d->d_ino    = ++odn->odn_NextDirEntryIndex;
  2092.                     d->d_namlen    = strlen(d->d_name);
  2093.  
  2094.                     result = d;
  2095.                 }
  2096.                 else
  2097.                 {
  2098.                     /* Return the next volume in the list. */
  2099.                     if(odn->odn_NextNode != NULL && odn->odn_NextNode->ln_Succ != NULL)
  2100.                     {
  2101.                         ASSERT(sizeof(d->d_name) >= strlen(odn->odn_NextNode->ln_Name));
  2102.  
  2103.                         strcpy(d->d_name,odn->odn_NextNode->ln_Name);
  2104.  
  2105.                         odn->odn_NextNode = odn->odn_NextNode->ln_Succ;
  2106.  
  2107.                         d->d_ino    = odn->odn_NextDirEntryIndex++;
  2108.                         d->d_namlen    = strlen(d->d_name);
  2109.  
  2110.                         result = d;
  2111.                     }
  2112.                     else
  2113.                     {
  2114.                         errno = 0;
  2115.                     }
  2116.                 }
  2117.             }
  2118.             else
  2119.             {
  2120.                 if(odn->odn_NextDirEntryIndex == 0)
  2121.                 {
  2122.                     /* The first directory entry points
  2123.                      * back to the directory itself.
  2124.                      */
  2125.                     strcpy(d->d_name,".");
  2126.  
  2127.                     d->d_ino    = odn->odn_FIB.fib_DiskKey;
  2128.                     d->d_namlen    = strlen(d->d_name);
  2129.  
  2130.                     odn->odn_NextDirEntryIndex++;
  2131.                     result = d;
  2132.                 }
  2133.                 else if(odn->odn_NextDirEntryIndex == 1)
  2134.                 {
  2135.                     /* The second directory entry points
  2136.                      * to the parent directory.
  2137.                      */
  2138.                     strcpy(d->d_name,"..");
  2139.  
  2140.                     d->d_ino    = odn->odn_ParentDirKey;
  2141.                     d->d_namlen    = strlen(d->d_name);
  2142.  
  2143.                     odn->odn_NextDirEntryIndex++;
  2144.                     result = d;
  2145.                 }
  2146.                 else
  2147.                 {
  2148.                     ForbidDOS();
  2149.  
  2150.                     /* All other iterations pick up the
  2151.                      * next following directory entry.
  2152.                      */
  2153.                     if(ExNext(odn->odn_FileLock,&odn->odn_FIB))
  2154.                     {
  2155.                         ASSERT(sizeof(d->d_name) >= strlen(odn->odn_FIB.fib_FileName));
  2156.  
  2157.                         strcpy(d->d_name,odn->odn_FIB.fib_FileName);
  2158.  
  2159.                         d->d_ino    = odn->odn_FIB.fib_DiskKey;
  2160.                         d->d_namlen    = strlen(d->d_name);
  2161.  
  2162.                         result = d;
  2163.                     }
  2164.                     else
  2165.                     {
  2166.                         LONG error = IoErr();
  2167.  
  2168.                         if(error == ERROR_NO_MORE_ENTRIES)
  2169.                         {
  2170.                             errno = 0;
  2171.                         }
  2172.                         else
  2173.                         {
  2174.                             SetIoErr(error);
  2175.                             MapIoErrToErrno();
  2176.                         }
  2177.                     }
  2178.  
  2179.                     PermitDOS();
  2180.                 }
  2181.             }
  2182.         }
  2183.     }
  2184.  
  2185.     if(result != NULL)
  2186.         SHOWSTRING(result->d_name);
  2187.  
  2188.     return(result);
  2189. }
  2190.  
  2191. /******************************************************************************/
  2192.  
  2193. STATIC int
  2194. TranslateRelativePath(char **namePtr,char *replace,int maxReplaceLen)
  2195. {
  2196.     int result = ERROR;
  2197.     char * name;
  2198.  
  2199.     ASSERT(namePtr != NULL && (*namePtr) != NULL && replace != NULL);
  2200.  
  2201.     /* If we have a current directory all references should
  2202.      * be made relative to, do just that. Absolute paths
  2203.      * are not modified, though.
  2204.      */
  2205.     name = (*namePtr);
  2206.     if(NOT STRING_IS_EMPTY(CurrentDirName) && name[0] != '/')
  2207.     {
  2208.         int totalLen;
  2209.  
  2210.         SHOWMSG("Changing the directory name");
  2211.  
  2212.         /* Skip current dir modifiers, we just want the name. */
  2213.         if(strncmp(name,"./",2) == SAME)
  2214.             name += 2;
  2215.         else if (strcmp(name,".") == SAME)
  2216.             name = "";
  2217.  
  2218.         /* Get the current directory name and get
  2219.          * ready to attach the file name at the end.
  2220.          */
  2221.         totalLen = strlen(CurrentDirName);
  2222.  
  2223.         if(CurrentDirName[strlen(CurrentDirName)-1] != '/' &&
  2224.            CurrentDirName[strlen(CurrentDirName)-1] != ':' &&
  2225.            NOT STRING_IS_EMPTY(name))
  2226.         {
  2227.             totalLen++;
  2228.         }
  2229.  
  2230.         totalLen += strlen(name);
  2231.  
  2232.         /* Check if the complete string will fit. */
  2233.         if(totalLen < maxReplaceLen)
  2234.         {
  2235.             /* Put the file name together. */
  2236.             strcpy(replace,CurrentDirName);
  2237.             if(CurrentDirName[strlen(CurrentDirName)-1] != '/' && NOT STRING_IS_EMPTY(name))
  2238.                 strcat(replace,"/");
  2239.  
  2240.             strcat(replace,name);
  2241.  
  2242.             (*namePtr) = replace;
  2243.             SHOWSTRING(*namePtr);
  2244.  
  2245.             result = OK;
  2246.         }
  2247.         else
  2248.         {
  2249.             errno = ENAMETOOLONG;
  2250.         }
  2251.     }
  2252.     else
  2253.     {
  2254.         result = OK;
  2255.     }
  2256.  
  2257.     return(result);
  2258. }
  2259.  
  2260. /******************************************************************************/
  2261.  
  2262. int
  2263. amiga_mkdir(char *name,int mode)
  2264. {
  2265.     struct MangleInfo mi;
  2266.     BPTR dirLock;
  2267.     int result = ERROR;
  2268.  
  2269.     chkabort();
  2270.  
  2271.     ASSERT(name != NULL);
  2272.  
  2273.     ENTER();
  2274.     SHOWSTRING(name);
  2275.     SHOWVALUE(mode);
  2276.  
  2277.     if(MangleName(&name,&mi) == OK)
  2278.     {
  2279.         ForbidDOS();
  2280.  
  2281.         dirLock = CreateDir((STRPTR)name);
  2282.         if(dirLock != ZERO)
  2283.         {
  2284.             UnLock(dirLock);
  2285.             result = OK;
  2286.         }
  2287.         else
  2288.         {
  2289.             MapIoErrToErrno();
  2290.         }
  2291.  
  2292.         PermitDOS();
  2293.  
  2294.         UnmangleName(&name,&mi);
  2295.     }
  2296.  
  2297.     if(result == OK)
  2298.         result = amiga_chmod(name,mode);
  2299.  
  2300.     RETURN(result);
  2301.     return(result);
  2302. }
  2303.  
  2304. /******************************************************************************/
  2305.  
  2306. int
  2307. amiga_rmdir(char *name)
  2308. {
  2309.     struct MangleInfo mi;
  2310.     BPTR fileLock;
  2311.     int result = ERROR;
  2312.  
  2313.     chkabort();
  2314.  
  2315.     ENTER();
  2316.     SHOWSTRING(name);
  2317.  
  2318.     if(MangleName(&name,&mi) == OK)
  2319.     {
  2320.         ForbidDOS();
  2321.  
  2322.         fileLock = Lock(name,SHARED_LOCK);
  2323.         if(fileLock != ZERO)
  2324.         {
  2325.             struct FileInfoBlock __aligned fib;
  2326.  
  2327.             if(Examine(fileLock,&fib))
  2328.             {
  2329.                 UnLock(fileLock);
  2330.                 fileLock = ZERO;
  2331.  
  2332.                 /* Make sure that we get to remove a drawer,
  2333.                  * as the function name implies.
  2334.                  */
  2335.                 if(FIB_IS_DRAWER(&fib))
  2336.                 {
  2337.                     if(DeleteFile(name))
  2338.                         result = OK;
  2339.                     else
  2340.                         MapIoErrToErrno();
  2341.                 }
  2342.                 else
  2343.                 {
  2344.                     errno = ENOTDIR;
  2345.                 }
  2346.             }
  2347.             else
  2348.             {
  2349.                 MapIoErrToErrno();
  2350.             }
  2351.  
  2352.             UnLock(fileLock);
  2353.         }
  2354.         else
  2355.         {
  2356.             MapIoErrToErrno();
  2357.         }
  2358.  
  2359.         PermitDOS();
  2360.  
  2361.         UnmangleName(&name,&mi);
  2362.     }
  2363.  
  2364.     RETURN(result);
  2365.     return(result);
  2366. }
  2367.  
  2368. /******************************************************************************/
  2369.  
  2370. int
  2371. amiga_creat(char *name,int prot)
  2372. {
  2373.     struct MangleInfo mi;
  2374.     int result = ERROR;
  2375.  
  2376.     chkabort();
  2377.  
  2378.     ASSERT(name != NULL);
  2379.  
  2380.     ENTER();
  2381.     SHOWSTRING(name);
  2382.     SHOWVALUE(prot);
  2383.  
  2384.     if(MangleName(&name,&mi) == OK)
  2385.     {
  2386.         ForbidDOS();
  2387.         result = creat(name,prot);
  2388.         PermitDOS();
  2389.  
  2390.         UnmangleName(&name,&mi);
  2391.     }
  2392.  
  2393.     RETURN(result);
  2394.     return(result);
  2395. }
  2396.  
  2397. /******************************************************************************/
  2398.  
  2399. FILE *
  2400. amiga_fopen(char *name,char *mode)
  2401. {
  2402.     struct MangleInfo mi;
  2403.     FILE *result = NULL;
  2404.  
  2405.     chkabort();
  2406.  
  2407.     ASSERT(name != NULL && mode != NULL);
  2408.  
  2409.     ENTER();
  2410.     SHOWSTRING(name);
  2411.     SHOWSTRING(mode);
  2412.  
  2413.     if(MangleName(&name,&mi) == OK)
  2414.     {
  2415.         ForbidDOS();
  2416.         result = fopen(name,mode);
  2417.         PermitDOS();
  2418.  
  2419.         UnmangleName(&name,&mi);
  2420.     }
  2421.  
  2422.     RETURN(result);
  2423.     return(result);
  2424. }
  2425.  
  2426. /******************************************************************************/
  2427.  
  2428. int
  2429. amiga_rename(char *old,char *new)
  2430. {
  2431.     struct MangleInfo old_mi;
  2432.     struct MangleInfo new_mi;
  2433.     int result = ERROR;
  2434.  
  2435.     chkabort();
  2436.  
  2437.     ASSERT(old != NULL && new != NULL);
  2438.  
  2439.     ENTER();
  2440.     SHOWSTRING(old);
  2441.     SHOWSTRING(new);
  2442.  
  2443.     /* rename() causes the link named <from> to be renamed as <to>. If <to> exists,
  2444.      * it is first removed. Both <from> and <to> must be of the same type (that is,
  2445.      * both directories or both non-directories), and must reside on the same
  2446.      * file system.
  2447.      */
  2448.  
  2449.     if(MangleName(&old,&old_mi) == OK)
  2450.     {
  2451.         if(MangleName(&new,&new_mi) == OK)
  2452.         {
  2453.             ForbidDOS();
  2454.  
  2455.             D(("rename |%s| to |%s|",old,new));
  2456.  
  2457.             if(CANNOT Rename(old,new))
  2458.             {
  2459.                 LONG error = IoErr();
  2460.  
  2461.                 SHOWVALUE(error);
  2462.  
  2463.                 if(error == ERROR_OBJECT_EXISTS)
  2464.                 {
  2465.                     BPTR oldLock = Lock(old,SHARED_LOCK);
  2466.                     BPTR newLock = Lock(new,SHARED_LOCK);
  2467.  
  2468.                     if(oldLock != ZERO && newLock != ZERO && SameLock(oldLock,newLock) == LOCK_SAME)
  2469.                     {
  2470.                         result = OK;
  2471.                         error = OK;
  2472.  
  2473.                         SHOWMSG("Ok; same name");
  2474.  
  2475.                         UnLock(oldLock);
  2476.                         UnLock(newLock);
  2477.                     }
  2478.                     else
  2479.                     {
  2480.                         UnLock(oldLock);
  2481.                         UnLock(newLock);
  2482.  
  2483.                         if(DeleteFile(new))
  2484.                         {
  2485.                             if(Rename(old,new))
  2486.                             {
  2487.                                 result = OK;
  2488.                                 error = OK;
  2489.  
  2490.                                 SHOWMSG("Ok; after removing");
  2491.                             }
  2492.                             else
  2493.                             {
  2494.                                 error = IoErr();
  2495.                             }
  2496.                         }
  2497.                         else
  2498.                         {
  2499.                             error = IoErr();
  2500.                         }
  2501.                     }
  2502.                 }
  2503.  
  2504.                 if(error != OK)
  2505.                 {
  2506.                     SHOWVALUE(error);
  2507.  
  2508.                     SetIoErr(error);
  2509.                     MapIoErrToErrno();
  2510.                 }
  2511.             }
  2512.             else
  2513.             {
  2514.                 SHOWMSG("Ok");
  2515.  
  2516.                 result = OK;
  2517.             }
  2518.  
  2519.             PermitDOS();
  2520.  
  2521.             UnmangleName(&new,&new_mi);
  2522.         }
  2523.         else
  2524.         {
  2525.             SHOWMSG("MangleName new_mi failed");
  2526.         }
  2527.  
  2528.         UnmangleName(&old,&old_mi);
  2529.     }
  2530.     else
  2531.     {
  2532.         SHOWMSG("MangleName old_mi failed");
  2533.     }
  2534.  
  2535.     RETURN(result);
  2536.     return(result);
  2537. }
  2538.  
  2539. /******************************************************************************/
  2540.  
  2541. char *
  2542. amiga_getcwd(char *buf, size_t size)
  2543. {
  2544.     char *result = NULL;
  2545.  
  2546.     chkabort();
  2547.  
  2548.     ASSERT(buf != NULL);
  2549.  
  2550.     ENTER();
  2551.     SHOWVALUE(buf);
  2552.     SHOWVALUE(size);
  2553.  
  2554.     if(CurrentDirName[0] == '/')
  2555.     {
  2556.         strncpy(buf,CurrentDirName,size-1);
  2557.         buf[size-1] = '\0';
  2558.         result = buf;
  2559.     }
  2560.     else
  2561.     {
  2562.         BPTR oldDir;
  2563.  
  2564.         ForbidDOS();
  2565.  
  2566.         oldDir = CurrentDir(ZERO);
  2567.  
  2568.         if(NameFromLock(oldDir,buf,size))
  2569.         {
  2570.             if(MapFileNameAmigaToUnix(buf,buf,size) == OK)
  2571.                 result = buf;
  2572.         }
  2573.         else
  2574.         {
  2575.             MapIoErrToErrno();
  2576.         }
  2577.  
  2578.         CurrentDir(oldDir);
  2579.  
  2580.         PermitDOS();
  2581.     }
  2582.  
  2583.     SHOWSTRING(result);
  2584.  
  2585.     RETURN(result);
  2586.     return(result);
  2587. }
  2588.  
  2589. /******************************************************************************/
  2590.  
  2591. #define SET_FILESIZE_ERROR (-1)
  2592.  
  2593. int
  2594. amiga_ftruncate(int fd,off_t size)
  2595. {
  2596.     struct UFB * ufb;
  2597.     int result = ERROR;
  2598.  
  2599.     chkabort();
  2600.  
  2601.     ENTER();
  2602.     SHOWVALUE(fd);
  2603.     SHOWVALUE(size);
  2604.  
  2605.     ufb = chkufb(fd);
  2606.     if(ufb != NULL)
  2607.     {
  2608.         ForbidDOS();
  2609.  
  2610.         if(SetFileSize((BPTR)ufb->ufbfh,size,OFFSET_BEGINNING) != SET_FILESIZE_ERROR)
  2611.             result = OK;
  2612.         else
  2613.             MapIoErrToErrno();
  2614.  
  2615.         PermitDOS();
  2616.     }
  2617.     else
  2618.     {
  2619.         errno = EBADF;
  2620.     }
  2621.  
  2622.     RETURN(result);
  2623.     return(result);
  2624. }
  2625.  
  2626. /******************************************************************************/
  2627.  
  2628. int
  2629. amiga_accept(int sockfd,struct sockaddr *cliaddr,int *addrlen)
  2630. {
  2631.     struct UFB * ufb;
  2632.     int result = ERROR;
  2633.  
  2634.     chkabort();
  2635.  
  2636.     ASSERT(cliaddr != NULL && addrlen != NULL);
  2637.  
  2638.     ENTER();
  2639.     SHOWVALUE(sockfd);
  2640.     SHOWVALUE(cliaddr);
  2641.     SHOWVALUE(addrlen);
  2642.  
  2643.     ufb = chkufb(sockfd);
  2644.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2645.         result = accept(ufb->ufbfh,cliaddr,(LONG *)addrlen);
  2646.     else
  2647.         errno = ENOTSOCK;
  2648.  
  2649.     RETURN(result);
  2650.     return(result);
  2651. }
  2652.  
  2653. /******************************************************************************/
  2654.  
  2655. int
  2656. amiga_bind(int sockfd,struct sockaddr *name,int namelen)
  2657. {
  2658.     struct UFB * ufb;
  2659.     int result = ERROR;
  2660.  
  2661.     chkabort();
  2662.  
  2663.     ASSERT(name != NULL);
  2664.  
  2665.     ENTER();
  2666.     SHOWVALUE(sockfd);
  2667.     SHOWVALUE(name);
  2668.     SHOWVALUE(namelen);
  2669.  
  2670.     ufb = chkufb(sockfd);
  2671.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2672.         result = bind(ufb->ufbfh,name,namelen);
  2673.     else
  2674.         errno = ENOTSOCK;
  2675.  
  2676.     RETURN(result);
  2677.     return(result);
  2678. }
  2679.  
  2680. /******************************************************************************/
  2681.  
  2682. int
  2683. amiga_close(int fd)
  2684. {
  2685.     struct UFB * ufb;
  2686.     int result = ERROR;
  2687.  
  2688.     chkabort();
  2689.  
  2690.     ENTER();
  2691.     SHOWVALUE(fd);
  2692.  
  2693.     ufb = chkufb(fd);
  2694.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2695.     {
  2696.         result = CloseSocket(ufb->ufbfh);
  2697.         CLEAR_FLAG(ufb->ufbflg,UFB_IS_SOCKET);
  2698.  
  2699.         /* Make sure that the descriptor looks like a file again. */
  2700.         RestoreDescriptor(ufb);
  2701.  
  2702.         close(fd);
  2703.     }
  2704.     else
  2705.     {
  2706.         if(ufb != NULL)
  2707.         {
  2708.             /* Don't close the stdio streams! */
  2709.             if(fd == 0 || fd == 1 || fd == 2)
  2710.             {
  2711.                 D(("Attempt to muck with fd #%ld!",fd));
  2712.  
  2713.                 errno = EBADF;
  2714.             }
  2715.             else
  2716.             {
  2717.                 char fileName[MAX_FILENAME_LEN];
  2718.                 BOOL removeIt = FALSE;
  2719.  
  2720.                 if(FLAG_IS_SET(ufb->ufbflg,UFB_UNLINK))
  2721.                 {
  2722.                     removeIt = NameFromFH((BPTR)ufb->ufbfh,fileName,sizeof(fileName));
  2723.  
  2724.                     CLEAR_FLAG(ufb->ufbflg,UFB_UNLINK);
  2725.                 }
  2726.  
  2727.                 CleanupFileLocks(fd);
  2728.  
  2729.                 result = close(fd);
  2730.  
  2731.                 if(removeIt)
  2732.                     DeleteFile(fileName);
  2733.             }
  2734.         }
  2735.         else
  2736.         {
  2737.             errno = EBADF;
  2738.         }
  2739.     }
  2740.  
  2741.     RETURN(result);
  2742.     return(result);
  2743. }
  2744.  
  2745. /******************************************************************************/
  2746.  
  2747. int
  2748. amiga_connect(int sockfd,struct sockaddr *name,int namelen)
  2749. {
  2750.     struct UFB * ufb;
  2751.     int result = ERROR;
  2752.  
  2753.     chkabort();
  2754.  
  2755.     ASSERT(name != NULL && namelen > 0);
  2756.  
  2757.     ENTER();
  2758.     SHOWVALUE(sockfd);
  2759.     SHOWVALUE(name);
  2760.     SHOWVALUE(namelen);
  2761.  
  2762.     ufb = chkufb(sockfd);
  2763.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2764.         result = connect(ufb->ufbfh,name,namelen);
  2765.     else
  2766.         errno = ENOTSOCK;
  2767.  
  2768.     RETURN(result);
  2769.     return(result);
  2770. }
  2771.  
  2772. /******************************************************************************/
  2773.  
  2774. int
  2775. amiga_getpeername(int sockfd,struct sockaddr *name,int *namelen)
  2776. {
  2777.     struct UFB * ufb;
  2778.     int result = ERROR;
  2779.  
  2780.     chkabort();
  2781.  
  2782.     ASSERT(name != NULL && namelen != NULL);
  2783.  
  2784.     ENTER();
  2785.     SHOWVALUE(sockfd);
  2786.     SHOWVALUE(name);
  2787.     SHOWVALUE(namelen);
  2788.  
  2789.     ufb = chkufb(sockfd);
  2790.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2791.         result = getpeername(ufb->ufbfh,name,(LONG *)namelen);
  2792.     else
  2793.         errno = ENOTSOCK;
  2794.  
  2795.     RETURN(result);
  2796.     return(result);
  2797. }
  2798.  
  2799. /******************************************************************************/
  2800.  
  2801. int
  2802. amiga_getsockopt(int sockfd,int level,int optname,VOID *optval,int *optlen)
  2803. {
  2804.     struct UFB * ufb;
  2805.     int result = ERROR;
  2806.  
  2807.     chkabort();
  2808.  
  2809.     ASSERT(optval != NULL && optlen != NULL);
  2810.  
  2811.     ENTER();
  2812.     SHOWVALUE(sockfd);
  2813.     SHOWVALUE(level);
  2814.     SHOWVALUE(optname);
  2815.     SHOWVALUE(optval);
  2816.     SHOWVALUE(optlen);
  2817.  
  2818.     ufb = chkufb(sockfd);
  2819.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2820.         result = getsockopt(ufb->ufbfh,level,optname,optval,(LONG *)optlen);
  2821.     else
  2822.         errno = ENOTSOCK;
  2823.  
  2824.     RETURN(result);
  2825.     return(result);
  2826. }
  2827.  
  2828. /******************************************************************************/
  2829.  
  2830. int
  2831. amiga_ioctl(int fd,unsigned long request,char *arg)
  2832. {
  2833.     struct UFB * ufb;
  2834.     int result = ERROR;
  2835.  
  2836.     chkabort();
  2837.  
  2838.     ASSERT(arg != NULL);
  2839.  
  2840.     ENTER();
  2841.     SHOWVALUE(fd);
  2842.     SHOWVALUE(request);
  2843.     SHOWVALUE(arg);
  2844.  
  2845.     ufb = chkufb(fd);
  2846.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2847.         result = IoctlSocket(ufb->ufbfh,request,arg);
  2848.     else
  2849.         errno = ENOTSOCK;
  2850.  
  2851.     RETURN(result);
  2852.     return(result);
  2853. }
  2854.  
  2855. /******************************************************************************/
  2856.  
  2857. int
  2858. amiga_listen(int sockfd,int backlog)
  2859. {
  2860.     struct UFB * ufb;
  2861.     int result = ERROR;
  2862.  
  2863.     chkabort();
  2864.  
  2865.     ENTER();
  2866.     SHOWVALUE(sockfd);
  2867.     SHOWVALUE(backlog);
  2868.  
  2869.     ufb = chkufb(sockfd);
  2870.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2871.         result = listen(ufb->ufbfh,backlog);
  2872.     else
  2873.         errno = ENOTSOCK;
  2874.  
  2875.     RETURN(result);
  2876.     return(result);
  2877. }
  2878.  
  2879. /******************************************************************************/
  2880.  
  2881. int
  2882. amiga_read(int fd,VOID *data,unsigned int size)
  2883. {
  2884.     struct UFB * ufb;
  2885.     int result;
  2886.  
  2887.     chkabort();
  2888.  
  2889.     ASSERT(data != NULL);
  2890.  
  2891.     ENTER();
  2892.     SHOWVALUE(fd);
  2893.     SHOWVALUE(data);
  2894.     SHOWVALUE(size);
  2895.  
  2896.     ufb = chkufb(fd);
  2897.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2898.     {
  2899.         SHOWMSG("input from socket");
  2900.         result = recv(ufb->ufbfh,data,size,0);
  2901.     }
  2902.     else
  2903.     {
  2904.         SHOWMSG("input from file");
  2905.         ForbidDOS();
  2906.         result = read(fd,data,size);
  2907.         PermitDOS();
  2908.     }
  2909.  
  2910.     RETURN(result);
  2911.     return(result);
  2912. }
  2913.  
  2914. /******************************************************************************/
  2915.  
  2916. int
  2917. amiga_recvfrom(int sockfd,VOID *buff,int len,int flags,struct sockaddr *from,int *fromlen)
  2918. {
  2919.     struct UFB * ufb;
  2920.     int result = ERROR;
  2921.  
  2922.     chkabort();
  2923.  
  2924.     ASSERT(buff != NULL && from != NULL && fromlen != NULL);
  2925.  
  2926.     ENTER();
  2927.     SHOWVALUE(sockfd);
  2928.     SHOWVALUE(buff);
  2929.     SHOWVALUE(len);
  2930.     SHOWVALUE(flags);
  2931.     SHOWVALUE(from);
  2932.     SHOWVALUE(fromlen);
  2933.  
  2934.     ufb = chkufb(sockfd);
  2935.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2936.         result = recvfrom(ufb->ufbfh,buff,len,flags,from,(LONG *)fromlen);
  2937.     else
  2938.         errno = ENOTSOCK;
  2939.  
  2940.     RETURN(result);
  2941.     return(result);
  2942. }
  2943.  
  2944. /******************************************************************************/
  2945.  
  2946. STATIC VOID
  2947. MapDescriptorSets(
  2948.     const fd_set *    input_fds,
  2949.     int                num_input_fds,
  2950.     fd_set *        socket_fds,
  2951.     int *            max_socket_fd_ptr,
  2952.     fd_set *        file_fds,
  2953.     int *            max_file_fd_ptr)
  2954. {
  2955.     FD_ZERO(socket_fds);
  2956.     FD_ZERO(file_fds);
  2957.  
  2958.     /* This routine maps file descriptor sets
  2959.      * from one format to another. We map
  2960.      * socket descriptors and regular file
  2961.      * descriptor sets.
  2962.      */
  2963.     if(input_fds != NULL && num_input_fds > 0)
  2964.     {
  2965.         int max_socket_fd = (*max_socket_fd_ptr);
  2966.         int max_file_fd = (*max_file_fd_ptr);
  2967.         struct UFB * ufb;
  2968.         int i;
  2969.  
  2970.         for(i = 0 ; i < num_input_fds ; i++)
  2971.         {
  2972.             if(FD_ISSET(i,input_fds))
  2973.             {
  2974.                 D(("fd to wait on #%ld",i));
  2975.  
  2976.                 ufb = chkufb(i);
  2977.                 if(ufb != NULL)
  2978.                 {
  2979.                     /* Is this a socket descriptor? */
  2980.                     if(FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2981.                     {
  2982.                         D(("fd #%ld is a socket.\n",i));
  2983.  
  2984.                         FD_SET(ufb->ufbfh,socket_fds);
  2985.  
  2986.                         if(max_socket_fd < ufb->ufbfh)
  2987.                             max_socket_fd = ufb->ufbfh;
  2988.                     }
  2989.                     else
  2990.                     {
  2991.                         D(("fd #%ld is a file.\n",i));
  2992.  
  2993.                         /* We only watch files bound to
  2994.                          * console streams.
  2995.                          */
  2996.                         if(IsInteractive((BPTR)ufb->ufbfh))
  2997.                         {
  2998.                             FD_SET(i,file_fds);
  2999.  
  3000.                             if(max_file_fd < i)
  3001.                                 max_file_fd = i;
  3002.                         }
  3003.                     }
  3004.                 }
  3005.             }
  3006.         }
  3007.  
  3008.         (*max_socket_fd_ptr)    = max_socket_fd;
  3009.         (*max_file_fd_ptr)        = max_file_fd;
  3010.     }
  3011. }
  3012.  
  3013. STATIC VOID
  3014. RemapDescriptorSets(
  3015.     const fd_set *    socket_fds,
  3016.     int                max_socket_fd,
  3017.     const fd_set *    file_fds,
  3018.     int                max_file_fd,
  3019.     fd_set *        output_fds,
  3020.     int                num_output_fds)
  3021. {
  3022.     /* This routine reverses the mapping established
  3023.      * above. We map the file and socket descriptor
  3024.      * sets back into the original set.
  3025.      */
  3026.     if(output_fds != NULL)
  3027.     {
  3028.         int fd;
  3029.  
  3030.         FD_ZERO(output_fds);
  3031.  
  3032.         for(fd = 0 ; fd <= max_socket_fd ; fd++)
  3033.         {
  3034.             if(FD_ISSET(fd,socket_fds))
  3035.             {
  3036.                 struct UFB * ufb;
  3037.                 int output_fd;
  3038.  
  3039.                 for(output_fd = 0 ; output_fd < num_output_fds ; output_fd++)
  3040.                 {
  3041.                     ufb = chkufb(output_fd);
  3042.                     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET) && ufb->ufbfh == fd)
  3043.                     {
  3044.                         D(("fd #%ld has data",output_fd));
  3045.                         FD_SET(output_fd,output_fds);
  3046.                         break;
  3047.                     }
  3048.                 }
  3049.             }
  3050.         }
  3051.  
  3052.         for(fd = 0 ; fd <= max_file_fd ; fd++)
  3053.         {
  3054.             if(FD_ISSET(fd,file_fds))
  3055.             {
  3056.                 D(("fd #%ld has data",fd));
  3057.                 FD_SET(fd,output_fds);
  3058.             }
  3059.         }
  3060.     }
  3061. }
  3062.  
  3063. int
  3064. amiga_select(int num_fds,fd_set *read_fds,fd_set *write_fds,fd_set *except_fds,struct timeval *timeout)
  3065. {
  3066.     fd_set socket_read_fds;
  3067.     fd_set socket_write_fds;
  3068.     fd_set socket_except_fds;
  3069.     int max_socket_fd;
  3070.     fd_set file_read_fds;
  3071.     fd_set file_write_fds;
  3072.     fd_set file_except_fds;
  3073.     struct UFB * ufb;
  3074.     int max_file_fd;
  3075.     int result = 0;
  3076.  
  3077.     chkabort();
  3078.  
  3079.     ENTER();
  3080.  
  3081.     if(num_fds > FD_SETSIZE)
  3082.     {
  3083.         D(("Warning: %ld descriptor sets to wait on requested; only %ld available.",num_fds,FD_SETSIZE));
  3084.         num_fds = FD_SETSIZE;
  3085.     }
  3086.  
  3087.     max_socket_fd = -1;
  3088.     max_file_fd = -1;
  3089.  
  3090.     MapDescriptorSets(read_fds,        num_fds,    &socket_read_fds,    &max_socket_fd,    &file_read_fds,        &max_file_fd);
  3091.     MapDescriptorSets(write_fds,    num_fds,    &socket_write_fds,    &max_socket_fd,    &file_write_fds,    &max_file_fd);
  3092.     MapDescriptorSets(except_fds,    num_fds,    &socket_except_fds,    &max_socket_fd,    &file_except_fds,    &max_file_fd);
  3093.  
  3094.     D(("number of socket fds to work on == %ld",max_socket_fd+1));
  3095.     D(("number of file   fds to work on == %ld",max_file_fd+1));
  3096.  
  3097.     /* Wait for socket input? */
  3098.     if(max_socket_fd != -1)
  3099.     {
  3100.         /* Wait for file input, too? */
  3101.         if(max_file_fd != -1 && (timeout == NULL || timeout->tv_secs > 0 || timeout->tv_micro > 0))
  3102.         {
  3103.             struct timeval stopWhen;
  3104.             struct timeval zero;
  3105.             BOOL gotSomething;
  3106.             ULONG breakMask;
  3107.             int i;
  3108.  
  3109.             /* We are going to poll all streams; for the timeout
  3110.              * feature to work, we absolutely must know when to
  3111.              * stop polling.
  3112.              *
  3113.              * Why aren't we using asynchronous DOS packets?
  3114.              * The answer is that once a packet is sent, you
  3115.              * cannot easily abort it. Polling is safer in
  3116.              * that respect. Yes, I know that ACTION_STACK
  3117.              * can be used to fake input to a console stream,
  3118.              * but I'd rather not rely upon it.
  3119.              */
  3120.             if(timeout != NULL)
  3121.             {
  3122.                 GetSysTime((APTR)&stopWhen);
  3123.                 AddTime((APTR)&stopWhen,(APTR)timeout);
  3124.             }
  3125.             else
  3126.             {
  3127.                 /* No timeout, poll until we are interrupted
  3128.                  * or get input from any of the files. It's
  3129.                  * not really necessary to initialize this
  3130.                  * timeval, but it keeps the compiler happy.
  3131.                  */
  3132.                 memset(&stopWhen,0,sizeof(stopWhen));
  3133.             }
  3134.  
  3135.             while(TRUE)
  3136.             {
  3137.                 /* Check for break signal. */
  3138.                 chkabort();
  3139.  
  3140.                 /* Delay for a tick to avoid busy-waiting. */
  3141.                 Delay(1);
  3142.  
  3143.                 /* This tells WaitSelect() to poll the sockets for input. */
  3144.                 zero.tv_secs    = 0;
  3145.                 zero.tv_micro    = 0;
  3146.  
  3147.                 /* Signals to stop on; we want to stop when a break signal arrives. */
  3148.                 if(AllowBreak)
  3149.                     breakMask = SIGBREAKF_CTRL_C;
  3150.                 else
  3151.                     breakMask = 0;
  3152.  
  3153.                 /* Check for socket input. */
  3154.                 result = WaitSelect(max_socket_fd+1,&socket_read_fds,&socket_write_fds,&socket_except_fds,&zero,&breakMask);
  3155.  
  3156.                 /* Stop if a break signal arrives. */
  3157.                 if((result < 0 && errno == EINTR) || FLAG_IS_SET(breakMask,SIGBREAKF_CTRL_C))
  3158.                     raise(SIGINT);
  3159.  
  3160.                 /* Stop if the return value from WaitSelect is negative. */
  3161.                 if(result < 0)
  3162.                     break;
  3163.  
  3164.                 /* Did we get any socket input? */
  3165.                 gotSomething = (BOOL)(result > 0);
  3166.                 if(NOT gotSomething)
  3167.                 {
  3168.                     /* Check all files for input. We also poll
  3169.                      * them for input, but each with a little
  3170.                      * delay of about 1/50 of a second. We stop
  3171.                      * as soon as we find one file that has
  3172.                      * input in it.
  3173.                      */
  3174.                     for(i = 0 ; i <= max_file_fd ; i++)
  3175.                     {
  3176.                         if(FD_ISSET(i,&file_read_fds) ||
  3177.                            FD_ISSET(i,&file_write_fds) ||
  3178.                            FD_ISSET(i,&file_except_fds))
  3179.                         {
  3180.                             ufb = chkufb(i);
  3181.                             if(ufb != NULL)
  3182.                             {
  3183.                                 if(WaitForChar((BPTR)ufb->ufbfh,1))
  3184.                                 {
  3185.                                     gotSomething = TRUE;
  3186.                                     break;
  3187.                                 }
  3188.                             }
  3189.                         }
  3190.                     }
  3191.                 }
  3192.  
  3193.                 /* Did we get any input at all? */
  3194.                 if(gotSomething)
  3195.                 {
  3196.                     BOOL gotInput;
  3197.  
  3198.                     /* Now retest all files and remember
  3199.                      * those that had input.
  3200.                      */
  3201.                     for(i = 0 ; i <= max_file_fd ; i++)
  3202.                     {
  3203.                         gotInput = FALSE;
  3204.  
  3205.                         if(FD_ISSET(i,&file_read_fds) ||
  3206.                            FD_ISSET(i,&file_write_fds) ||
  3207.                            FD_ISSET(i,&file_except_fds))
  3208.                         {
  3209.                             ufb = chkufb(i);
  3210.                             if(ufb != NULL)
  3211.                             {
  3212.                                 /* Does this one have input? */
  3213.                                 gotInput = WaitForChar((BPTR)ufb->ufbfh,1);
  3214.                             }
  3215.                         }
  3216.  
  3217.                         if(gotInput)
  3218.                         {
  3219.                             /* Mark one more descriptor as
  3220.                              * having input.
  3221.                              */
  3222.                             result++;
  3223.                         }
  3224.                         else
  3225.                         {
  3226.                             /* Mark this descriptor as
  3227.                              * not having any input.
  3228.                              */
  3229.                             FD_CLR(i,&file_read_fds);
  3230.                             FD_CLR(i,&file_write_fds);
  3231.                             FD_CLR(i,&file_except_fds);
  3232.                         }
  3233.                     }
  3234.                 }
  3235.  
  3236.                 /* Did we get any input? If so, stop polling. */
  3237.                 if(result > 0)
  3238.                     break;
  3239.  
  3240.                 /* If a timeout was set, check if we are already
  3241.                  * beyond the point of time when we should have
  3242.                  * stopped polling.
  3243.                  */
  3244.                 if(timeout != NULL)
  3245.                 {
  3246.                     struct timeval now;
  3247.  
  3248.                     GetSysTime((APTR)&now);
  3249.  
  3250.                     if((-CmpTime((APTR)&now,(APTR)&stopWhen)) >= 0)
  3251.                         break;
  3252.                 }
  3253.             }
  3254.         }
  3255.         else
  3256.         {
  3257.             ULONG breakMask;
  3258.  
  3259.             if(AllowBreak)
  3260.                 breakMask = SIGBREAKF_CTRL_C;
  3261.             else
  3262.                 breakMask = 0;
  3263.  
  3264.             result = WaitSelect(max_socket_fd+1,&socket_read_fds,&socket_write_fds,&socket_except_fds,timeout,&breakMask);
  3265.             if((result < 0 && errno == EINTR) || FLAG_IS_SET(breakMask,SIGBREAKF_CTRL_C))
  3266.                 raise(SIGINT);
  3267.         }
  3268.     }
  3269.     else
  3270.     {
  3271.         /* Wait for file input? */
  3272.         if(max_file_fd != -1 && (timeout == NULL || timeout->tv_secs > 0 || timeout->tv_micro > 0))
  3273.         {
  3274.             struct timeval stopWhen;
  3275.             BOOL gotSomething;
  3276.             int i;
  3277.  
  3278.             if(timeout != NULL)
  3279.             {
  3280.                 GetSysTime((APTR)&stopWhen);
  3281.                 AddTime((APTR)&stopWhen,(APTR)timeout);
  3282.             }
  3283.             else
  3284.             {
  3285.                 memset(&stopWhen,0,sizeof(stopWhen));
  3286.             }
  3287.  
  3288.             while(TRUE)
  3289.             {
  3290.                 chkabort();
  3291.  
  3292.                 Delay(1);
  3293.  
  3294.                 gotSomething = FALSE;
  3295.                 for(i = 0 ; i <= max_file_fd ; i++)
  3296.                 {
  3297.                     if(FD_ISSET(i,&file_read_fds) ||
  3298.                        FD_ISSET(i,&file_write_fds) ||
  3299.                        FD_ISSET(i,&file_except_fds))
  3300.                     {
  3301.                         ufb = chkufb(i);
  3302.                         if(ufb != NULL)
  3303.                         {
  3304.                             if(WaitForChar((BPTR)ufb->ufbfh,1))
  3305.                             {
  3306.                                 gotSomething = TRUE;
  3307.                                 break;
  3308.                             }
  3309.                         }
  3310.                     }
  3311.                 }
  3312.  
  3313.                 if(gotSomething)
  3314.                 {
  3315.                     BOOL gotInput;
  3316.  
  3317.                     for(i = 0 ; i <= max_file_fd ; i++)
  3318.                     {
  3319.                         gotInput = FALSE;
  3320.  
  3321.                         if(FD_ISSET(i,&file_read_fds) ||
  3322.                            FD_ISSET(i,&file_write_fds) ||
  3323.                            FD_ISSET(i,&file_except_fds))
  3324.                         {
  3325.                             ufb = chkufb(i);
  3326.                             if(ufb != NULL)
  3327.                             {
  3328.                                 /* Does this one have input? */
  3329.                                 gotInput = WaitForChar((BPTR)ufb->ufbfh,1);
  3330.                             }
  3331.                         }
  3332.  
  3333.                         if(gotInput)
  3334.                         {
  3335.                             result++;
  3336.                         }
  3337.                         else
  3338.                         {
  3339.                             FD_CLR(i,&file_read_fds);
  3340.                             FD_CLR(i,&file_write_fds);
  3341.                             FD_CLR(i,&file_except_fds);
  3342.                         }
  3343.                     }
  3344.                 }
  3345.  
  3346.                 if(result > 0)
  3347.                     break;
  3348.  
  3349.                 if(timeout != NULL)
  3350.                 {
  3351.                     struct timeval now;
  3352.  
  3353.                     GetSysTime((APTR)&now);
  3354.  
  3355.                     if((-CmpTime((APTR)&now,(APTR)&stopWhen)) >= 0)
  3356.                         break;
  3357.                 }
  3358.             }
  3359.         }
  3360.     }
  3361.  
  3362.     /* The descriptor sets remain unchanged in
  3363.      * case of error.
  3364.      */
  3365.     if(result >= 0)
  3366.     {
  3367.         RemapDescriptorSets(&socket_read_fds,    max_socket_fd,    &file_read_fds,        max_file_fd,    read_fds,    num_fds);
  3368.         RemapDescriptorSets(&socket_write_fds,    max_socket_fd,    &file_write_fds,    max_file_fd,    write_fds,    num_fds);
  3369.         RemapDescriptorSets(&socket_except_fds,    max_socket_fd,    &file_except_fds,    max_file_fd,    except_fds,    num_fds);
  3370.     }
  3371.  
  3372.     RETURN(result);
  3373.     return(result);
  3374. }
  3375.  
  3376. /******************************************************************************/
  3377.  
  3378. int
  3379. amiga_sendto(int sockfd,VOID *buff,int len,int flags,struct sockaddr *to,int tolen)
  3380. {
  3381.     struct UFB * ufb;
  3382.     int result = ERROR;
  3383.  
  3384.     chkabort();
  3385.  
  3386.     ASSERT(buff != NULL && to != NULL);
  3387.  
  3388.     ENTER();
  3389.     SHOWVALUE(sockfd);
  3390.     SHOWVALUE(buff);
  3391.     SHOWVALUE(len);
  3392.     SHOWVALUE(flags);
  3393.     SHOWVALUE(to);
  3394.     SHOWVALUE(tolen);
  3395.  
  3396.     ufb = chkufb(sockfd);
  3397.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  3398.         result = sendto(ufb->ufbfh,buff,len,flags,to,tolen);
  3399.     else
  3400.         errno = ENOTSOCK;
  3401.  
  3402.     RETURN(result);
  3403.     return(result);
  3404. }
  3405.  
  3406. /******************************************************************************/
  3407.  
  3408. int
  3409. amiga_setsockopt(int sockfd,int level,int optname,VOID *optval,int optlen)
  3410. {
  3411.     struct UFB * ufb;
  3412.     int result = ERROR;
  3413.  
  3414.     chkabort();
  3415.  
  3416.     ASSERT(optval != NULL);
  3417.  
  3418.     ENTER();
  3419.     SHOWVALUE(sockfd);
  3420.     SHOWVALUE(level);
  3421.     SHOWVALUE(optname);
  3422.     SHOWVALUE(optval);
  3423.     SHOWVALUE(optlen);
  3424.  
  3425.     ufb = chkufb(sockfd);
  3426.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  3427.         result = setsockopt(ufb->ufbfh,level,optname,optval,optlen);
  3428.     else
  3429.         errno = ENOTSOCK;
  3430.  
  3431.     RETURN(result);
  3432.     return(result);
  3433. }
  3434.  
  3435. /******************************************************************************/
  3436.  
  3437. int
  3438. amiga_socket(int domain,int type,int protocol)
  3439. {
  3440.     int result = ERROR;
  3441.     int fd;
  3442.  
  3443.     chkabort();
  3444.  
  3445.     ENTER();
  3446.     SHOWVALUE(domain);
  3447.     SHOWVALUE(type);
  3448.     SHOWVALUE(protocol);
  3449.  
  3450.     /* We open a regular file that is guaranteed to
  3451.      * open in any case and then attach a socket
  3452.      * in place of the original file handle.
  3453.      */
  3454.     fd = open("NIL:",O_RDWR,0777);
  3455.     if(fd != -1)
  3456.     {
  3457.         struct UFB * ufb;
  3458.  
  3459.         ufb = chkufb(fd);
  3460.         if(ufb != NULL)
  3461.         {
  3462.             /* Save the original file handle value. */
  3463.             if(SaveDescriptor(ufb))
  3464.             {
  3465.                 int sockfd;
  3466.  
  3467.                 /* Now create the real socket. */
  3468.                 sockfd = socket(domain,type,protocol);
  3469.                 if(sockfd != -1)
  3470.                 {
  3471.                     /* Put the socket in place of the file handle. */
  3472.                     SET_FLAG(ufb->ufbflg,UFB_IS_SOCKET);
  3473.                     ufb->ufbfh = sockfd;
  3474.  
  3475.                     result = fd;
  3476.                 }
  3477.                 else
  3478.                 {
  3479.                     close(fd);
  3480.                 }
  3481.             }
  3482.             else
  3483.             {
  3484.                 close(fd);
  3485.                 errno = ENOMEM;
  3486.             }
  3487.         }
  3488.         else
  3489.         {
  3490.             close(fd);
  3491.             errno = EBADF;
  3492.         }
  3493.     }
  3494.  
  3495.     RETURN(result);
  3496.     return(result);
  3497. }
  3498.  
  3499. /******************************************************************************/
  3500.  
  3501. int
  3502. amiga_write(int fd,VOID *data,unsigned int size)
  3503. {
  3504.     struct UFB * ufb;
  3505.     int result;
  3506.  
  3507.     chkabort();
  3508.  
  3509.     ASSERT(data != NULL);
  3510.  
  3511.     ENTER();
  3512.     SHOWVALUE(fd);
  3513.     SHOWVALUE(data);
  3514.     SHOWVALUE(size);
  3515.  
  3516.     ufb = chkufb(fd);
  3517.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  3518.     {
  3519.         result = send(ufb->ufbfh,data,size,0);
  3520.     }
  3521.     else
  3522.     {
  3523.         ForbidDOS();
  3524.         result = write(fd,data,size);
  3525.         PermitDOS();
  3526.     }
  3527.  
  3528.     RETURN(result);
  3529.     return(result);
  3530. }
  3531.  
  3532. /******************************************************************************/
  3533.  
  3534. STATIC VOID
  3535. ConvertFileInfoToStat(
  3536.     struct MsgPort * port,
  3537.     struct FileInfoBlock * fib,
  3538.     struct stat * st)
  3539. {
  3540.     ULONG flags;
  3541.     int mode;
  3542.     long time;
  3543.  
  3544.     /* This routine converts the contents of a FileInfoBlock
  3545.      * into information to fill a Unix-like stat data structure
  3546.      * with.
  3547.      */
  3548.     flags = fib->fib_Protection ^ (FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE);
  3549.  
  3550.     if(FIB_IS_DRAWER(fib))
  3551.         mode = S_IFDIR;
  3552.     else
  3553.         mode = S_IFREG;
  3554.  
  3555.     if(FLAG_IS_SET(flags,FIBF_READ))
  3556.         SET_FLAG(mode,S_IRUSR);
  3557.  
  3558.     if(FLAG_IS_SET(flags,FIBF_WRITE) && FLAG_IS_SET(flags,FIBF_DELETE))
  3559.         SET_FLAG(mode,S_IWUSR);
  3560.  
  3561.     if(FLAG_IS_SET(flags,FIBF_EXECUTE))
  3562.         SET_FLAG(mode,S_IXUSR);
  3563.  
  3564.  
  3565.     if(FLAG_IS_SET(flags,FIBF_GRP_READ))
  3566.         SET_FLAG(mode,S_IRGRP);
  3567.  
  3568.     if(FLAG_IS_SET(flags,FIBF_GRP_WRITE) && FLAG_IS_SET(flags,FIBF_GRP_DELETE))
  3569.         SET_FLAG(mode,S_IWGRP);
  3570.  
  3571.     if(FLAG_IS_SET(flags,FIBF_GRP_EXECUTE))
  3572.         SET_FLAG(mode,S_IXGRP);
  3573.  
  3574.  
  3575.     if(FLAG_IS_SET(flags,FIBF_OTR_READ))
  3576.         SET_FLAG(mode,S_IROTH);
  3577.  
  3578.     if(FLAG_IS_SET(flags,FIBF_OTR_WRITE) && FLAG_IS_SET(flags,FIBF_OTR_DELETE))
  3579.         SET_FLAG(mode,S_IWOTH);
  3580.  
  3581.     if(FLAG_IS_SET(flags,FIBF_OTR_EXECUTE))
  3582.         SET_FLAG(mode,S_IXOTH);
  3583.  
  3584.     time = fib->fib_Date.ds_Days * 24*60*60 +
  3585.            fib->fib_Date.ds_Minute * 60 +
  3586.           (fib->fib_Date.ds_Tick / TICKS_PER_SECOND);
  3587.  
  3588.     memset(st,0,sizeof(*st));
  3589.  
  3590.     st->st_dev        = (u_long)port;
  3591.     st->st_ino        = fib->fib_DiskKey;
  3592.     st->st_mode        = mode;
  3593.     st->st_mtime    = UNIX_TIME_OFFSET + time + 60*MinutesWest;    /* translate from local time to UTC */
  3594.     st->st_atime    = st->st_mtime;
  3595.     st->st_ctime    = st->st_mtime;
  3596.     st->st_uid        = fib->fib_OwnerUID;
  3597.     st->st_gid        = fib->fib_OwnerGID;
  3598.  
  3599.     if(FIB_IS_FILE(fib))
  3600.     {
  3601.         st->st_nlink = 1;
  3602.         st->st_size  = fib->fib_Size;
  3603.     }
  3604.     else
  3605.     {
  3606.         st->st_nlink = 2;
  3607.     }
  3608. }
  3609.  
  3610. int
  3611. amiga_stat(char *name, struct stat *st)
  3612. {
  3613.     char localName[MAX_FILENAME_LEN];
  3614.     struct MangleInfo mi;
  3615.     int result = ERROR;
  3616.  
  3617.     chkabort();
  3618.  
  3619.     ASSERT(name != NULL && st != NULL);
  3620.  
  3621.     ENTER();
  3622.     SHOWSTRING(name);
  3623.     SHOWVALUE(st);
  3624.  
  3625.     if(TranslateRelativePath(&name,localName,sizeof(localName)) == OK)
  3626.     {
  3627.         char * originalName = name;
  3628.  
  3629.         if(MangleName(&name,&mi) == OK)
  3630.         {
  3631.             int len;
  3632.  
  3633.             SHOWSTRING(name);
  3634.             SHOWSTRING(originalName);
  3635.  
  3636.             len = strlen(name);
  3637.             if((strcmp(originalName,"/") == SAME) || (len > 1 && name[len-2] == ':' && name[len-1] == '/'))
  3638.             {
  3639.                 struct timeval now;
  3640.  
  3641.                 SHOWMSG("this is the virtual root directory");
  3642.  
  3643.                 /* This must be our virtual root directory.
  3644.                  * Make something up.
  3645.                  */
  3646.                 memset(st,0,sizeof(*st));
  3647.                 GetSysTime((APTR)&now);
  3648.  
  3649.                 /* Nobody may write to this "directory". */
  3650.                 st->st_dev        = (u_long)"Virtual Root Directory";
  3651.                 st->st_ino        = 1;
  3652.                 st->st_mode        = S_IFDIR|S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
  3653.                 st->st_nlink    = 2;
  3654.                 st->st_mtime    = UNIX_TIME_OFFSET + now.tv_secs + 60*MinutesWest;    /* translate from local time to UTC */
  3655.                 st->st_atime    = st->st_mtime;
  3656.                 st->st_ctime    = st->st_mtime;
  3657.  
  3658.                 result = OK;
  3659.             }
  3660.             else
  3661.             {
  3662.                 BPTR fileLock;
  3663.  
  3664.                 SHOWMSG("this is a drawer or a file");
  3665.  
  3666.                 ForbidDOS();
  3667.  
  3668.                 fileLock = Lock((STRPTR)name,SHARED_LOCK);
  3669.                 if(fileLock != ZERO)
  3670.                 {
  3671.                     struct FileInfoBlock __aligned fib;
  3672.  
  3673.                     if(Examine(fileLock,&fib))
  3674.                     {
  3675.                         BPTR parentDir;
  3676.  
  3677.                         /* Check if this is the root directory. */
  3678.                         parentDir = ParentDir(fileLock);
  3679.                         if(parentDir != ZERO)
  3680.                         {
  3681.                             /* This is not the root directory. */
  3682.                             UnLock(parentDir);
  3683.                         }
  3684.                         else
  3685.                         {
  3686.                             /* So this is the root directory. Make sure
  3687.                              * that we return proper protection bits for
  3688.                              * it, i.e. that the directory is always
  3689.                              * readable, writable, etc. This may be
  3690.                              * necessary since on the Amiga, root
  3691.                              * directories cannot have any protection
  3692.                              * bits set. Note that the "deletable"
  3693.                              * bits don't make much sense, but then
  3694.                              * these bits work together with the
  3695.                              * writable bits. The lowest four bits
  3696.                              * remain zero, which enables them all.
  3697.                              */
  3698.                             fib.fib_Protection = FIBF_OTR_READ |
  3699.                                                  FIBF_OTR_WRITE |
  3700.                                                  FIBF_OTR_EXECUTE |
  3701.                                                  FIBF_OTR_DELETE |
  3702.                                                  FIBF_GRP_READ |
  3703.                                                  FIBF_GRP_WRITE |
  3704.                                                  FIBF_GRP_EXECUTE |
  3705.                                                  FIBF_GRP_DELETE;
  3706.                         }
  3707.  
  3708.                         ConvertFileInfoToStat(((struct FileLock *)BADDR(fileLock))->fl_Task,&fib,st);
  3709.  
  3710.                         result = OK;
  3711.                     }
  3712.                     else
  3713.                     {
  3714.                         MapIoErrToErrno();
  3715.                     }
  3716.  
  3717.                     UnLock(fileLock);
  3718.                 }
  3719.                 else
  3720.                 {
  3721.                     LONG error = IoErr();
  3722.  
  3723.                     if(error == ERROR_OBJECT_IN_USE)
  3724.                     {
  3725.                         char parentName[MAX_FILENAME_LEN];
  3726.                         BPTR parentLock;
  3727.  
  3728.                         strcpy(parentName,name);
  3729.                         (*PathPart(parentName) = '\0');
  3730.  
  3731.                         parentLock = Lock(parentName,SHARED_LOCK);
  3732.                         if(parentLock != ZERO)
  3733.                         {
  3734.                             struct FileInfoBlock __aligned fib;
  3735.  
  3736.                             if(Examine(parentLock,&fib))
  3737.                             {
  3738.                                 STRPTR onlyFileName = FilePart(name);
  3739.  
  3740.                                 while(ExNext(parentLock,&fib))
  3741.                                 {
  3742.                                     if(Stricmp(fib.fib_FileName,onlyFileName) == SAME)
  3743.                                     {
  3744.                                         ConvertFileInfoToStat(((struct FileLock *)BADDR(parentLock))->fl_Task,&fib,st);
  3745.  
  3746.                                         result = OK;
  3747.                                         error = OK;
  3748.                                         break;
  3749.                                     }
  3750.                                 }
  3751.                             }
  3752.  
  3753.                             UnLock(parentLock);
  3754.                         }
  3755.                     }
  3756.  
  3757.                     if(error != OK)
  3758.                     {
  3759.                         SetIoErr(error);
  3760.  
  3761.                         MapIoErrToErrno();
  3762.                     }
  3763.                 }
  3764.  
  3765.                 PermitDOS();
  3766.             }
  3767.  
  3768.             if(result == OK)
  3769.             {
  3770.                 SHOWVALUE(st->st_dev);
  3771.                 SHOWVALUE(st->st_ino);
  3772.                 SHOWVALUE(st->st_size);
  3773.                 SHOWVALUE(st->st_nlink);
  3774.                 SHOWVALUE(st->st_mode);
  3775.                 SHOWVALUE(st->st_mtime);
  3776.                 SHOWVALUE(st->st_atime);
  3777.                 SHOWVALUE(st->st_ctime);
  3778.                 SHOWVALUE(st->st_uid);
  3779.                 SHOWVALUE(st->st_gid);
  3780.             }
  3781.             else
  3782.             {
  3783.                 SHOWVALUE(errno);
  3784.             }
  3785.  
  3786.             UnmangleName(&name,&mi);
  3787.         }
  3788.     }
  3789.  
  3790.     RETURN(result);
  3791.     return(result);
  3792. }
  3793.  
  3794. int
  3795. amiga_lstat(char *name, struct stat *statstruct)
  3796. {
  3797.     int result;
  3798.  
  3799.     chkabort();
  3800.  
  3801.     ENTER();
  3802.     SHOWSTRING(name);
  3803.     SHOWVALUE(statstruct);
  3804.  
  3805.     result = amiga_stat(name,statstruct);
  3806.  
  3807.     RETURN(result);
  3808.     return(result);
  3809. }
  3810.  
  3811. int
  3812. amiga_fstat(int fd,struct stat * st)
  3813. {
  3814.     struct UFB * ufb;
  3815.     int result = ERROR;
  3816.  
  3817.     chkabort();
  3818.  
  3819.     ASSERT(st != NULL);
  3820.  
  3821.     ENTER();
  3822.     SHOWVALUE(fd);
  3823.     SHOWVALUE(st);
  3824.  
  3825.     ufb = chkufb(fd);
  3826.     if(ufb != NULL)
  3827.     {
  3828.         if(FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  3829.         {
  3830.             long value;
  3831.             long size = sizeof(value);
  3832.  
  3833.             memset(st,0,sizeof(*st));
  3834.  
  3835.             st->st_dev    = (u_long)SocketBase;
  3836.             st->st_mode    = S_IFSOCK | S_IRUSR | S_IWUSR;
  3837.             st->st_uid    = geteuid();
  3838.             st->st_gid    = getegid();
  3839.  
  3840.             if(getsockopt(fd,SOL_SOCKET,SO_SNDBUF,&value,&size) == 0)
  3841.                 st->st_blksize = value;
  3842.  
  3843.             result = OK;
  3844.         }
  3845.         else
  3846.         {
  3847.             struct FileHandle * fileHandle = BADDR(ufb->ufbfh);
  3848.  
  3849.             /* Make sure that this stream doesn't
  3850.              * really refer to "NIL:".
  3851.              */
  3852.             if(fileHandle->fh_Type != NULL)
  3853.             {
  3854.                 struct FileInfoBlock __aligned fib;
  3855.  
  3856.                 ForbidDOS();
  3857.  
  3858.                 if(ExamineFH(ufb->ufbfh,&fib))
  3859.                 {
  3860.                     ConvertFileInfoToStat(fileHandle->fh_Type,&fib,st);
  3861.  
  3862.                     result = OK;
  3863.                 }
  3864.                 else
  3865.                 {
  3866.                     MapIoErrToErrno();
  3867.                 }
  3868.  
  3869.                 PermitDOS();
  3870.             }
  3871.             else
  3872.             {
  3873.                 struct timeval tv;
  3874.  
  3875.                 /* Make up some phony data for a NIL: file handle. */
  3876.                 memset(st,0,sizeof(*st));
  3877.  
  3878.                 GetSysTime((APTR)&tv);
  3879.  
  3880.                 st->st_dev        = (u_long)0;
  3881.                 st->st_mode        = S_IFREG | S_IRUSR | S_IWUSR;
  3882.                 st->st_mtime    = UNIX_TIME_OFFSET + tv.tv_secs + 60*MinutesWest;    /* translate from local time to UTC */
  3883.                 st->st_atime    = st->st_mtime;
  3884.                 st->st_ctime    = st->st_mtime;
  3885.  
  3886.                 result = OK;
  3887.             }
  3888.         }
  3889.     }
  3890.     else
  3891.     {
  3892.         errno = EBADF;
  3893.     }
  3894.  
  3895.     RETURN(result);
  3896.     return(result);
  3897. }
  3898.  
  3899. /******************************************************************************/
  3900.  
  3901. int
  3902. amiga_chmod(char *name,int mode)
  3903. {
  3904.     struct MangleInfo mi;
  3905.     ULONG flags = 0;
  3906.     int result = ERROR;
  3907.  
  3908.     chkabort();
  3909.  
  3910.     ASSERT(name != NULL);
  3911.  
  3912.     ENTER();
  3913.     SHOWSTRING(name);
  3914.     SHOWVALUE(mode);
  3915.  
  3916.     /* Convert the file access modes into
  3917.      * Amiga typical protection bits.
  3918.      */
  3919.     if(FLAG_IS_SET(mode,S_IRUSR))
  3920.         SET_FLAG(flags,FIBF_READ);
  3921.  
  3922.     if(FLAG_IS_SET(mode,S_IWUSR))
  3923.     {
  3924.         SET_FLAG(flags,FIBF_WRITE);
  3925.         SET_FLAG(flags,FIBF_DELETE);
  3926.     }
  3927.  
  3928.     if(FLAG_IS_SET(mode,S_IXUSR))
  3929.         SET_FLAG(flags,FIBF_EXECUTE);
  3930.  
  3931.  
  3932.     if(FLAG_IS_SET(mode,S_IRGRP))
  3933.         SET_FLAG(flags,FIBF_GRP_READ);
  3934.  
  3935.     if(FLAG_IS_SET(mode,S_IWGRP))
  3936.     {
  3937.         SET_FLAG(flags,FIBF_GRP_WRITE);
  3938.         SET_FLAG(flags,FIBF_GRP_DELETE);
  3939.     }
  3940.  
  3941.     if(FLAG_IS_SET(mode,S_IXGRP))
  3942.         SET_FLAG(flags,FIBF_GRP_EXECUTE);
  3943.  
  3944.  
  3945.     if(FLAG_IS_SET(mode,S_IROTH))
  3946.         SET_FLAG(flags,FIBF_OTR_READ);
  3947.  
  3948.     if(FLAG_IS_SET(mode,S_IWOTH))
  3949.     {
  3950.         SET_FLAG(flags,FIBF_OTR_WRITE);
  3951.         SET_FLAG(flags,FIBF_OTR_DELETE);
  3952.     }
  3953.  
  3954.     if(FLAG_IS_SET(mode,S_IXOTH))
  3955.         SET_FLAG(flags,FIBF_OTR_EXECUTE);
  3956.  
  3957.     flags ^= (FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE);
  3958.  
  3959.     if(MangleName(&name,&mi) == OK)
  3960.     {
  3961.         ForbidDOS();
  3962.  
  3963.         if(SetProtection(name,flags))
  3964.         {
  3965.             result = OK;
  3966.         }
  3967.         else
  3968.         {
  3969.             LONG error = IoErr();
  3970.  
  3971.             /* Note sure about this one; is it really that important
  3972.              * that the file attribute change succeeds? This is a definite
  3973.              * FIXME.
  3974.              */
  3975.             if(error == ERROR_OBJECT_IN_USE)
  3976.             {
  3977.                 result = OK;
  3978.             }
  3979.             else
  3980.             {
  3981.                 SetIoErr(error);
  3982.  
  3983.                 MapIoErrToErrno();
  3984.             }
  3985.         }
  3986.  
  3987.         PermitDOS();
  3988.  
  3989.         UnmangleName(&name,&mi);
  3990.     }
  3991.  
  3992.     RETURN(result);
  3993.     return(result);
  3994. }
  3995.  
  3996. /******************************************************************************/
  3997.  
  3998. int
  3999. amiga_dup(int fd)
  4000. {
  4001.     struct UFB * ufb;
  4002.     int result = ERROR;
  4003.  
  4004.     chkabort();
  4005.  
  4006.     ENTER();
  4007.     SHOWVALUE(fd);
  4008.  
  4009.     ufb = chkufb(fd);
  4010.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  4011.     {
  4012.         fd = open("NIL:",O_RDWR,0777);
  4013.         if(fd != -1)
  4014.         {
  4015.             struct UFB * ufb2;
  4016.  
  4017.             ufb2 = chkufb(fd);
  4018.             if(ufb2 != NULL)
  4019.             {
  4020.                 if(SaveDescriptor(ufb2))
  4021.                 {
  4022.                     int sockfd;
  4023.  
  4024.                     sockfd = Dup2Socket(ufb->ufbfh,-1);
  4025.                     if(sockfd != -1)
  4026.                     {
  4027.                         SET_FLAG(ufb2->ufbflg,UFB_IS_SOCKET);
  4028.                         ufb2->ufbfh = sockfd;
  4029.  
  4030.                         result = fd;
  4031.                     }
  4032.                     else
  4033.                     {
  4034.                         close(fd);
  4035.                     }
  4036.                 }
  4037.                 else
  4038.                 {
  4039.                     close(fd);
  4040.                     errno = ENOMEM;
  4041.                 }
  4042.             }
  4043.             else
  4044.             {
  4045.                 close(fd);
  4046.                 errno = EBADF;
  4047.             }
  4048.         }
  4049.     }
  4050.     else
  4051.     {
  4052.         errno = ENOTSOCK;
  4053.     }
  4054.  
  4055.     RETURN(result);
  4056.     return(result);
  4057. }
  4058.  
  4059. /******************************************************************************/
  4060.  
  4061. int
  4062. amiga_dup2(int old_fd,int new_fd)
  4063. {
  4064.     struct UFB * old_ufb;
  4065.     struct UFB * new_ufb;
  4066.     int result = ERROR;
  4067.  
  4068.     chkabort();
  4069.  
  4070.     ENTER();
  4071.     SHOWVALUE(old_fd);
  4072.     SHOWVALUE(new_fd);
  4073.  
  4074.     old_ufb = chkufb(old_fd);
  4075.     new_ufb = chkufb(new_fd);
  4076.  
  4077.     if(old_ufb != NULL && FLAG_IS_SET(old_ufb->ufbflg,UFB_IS_SOCKET) && new_ufb != NULL)
  4078.     {
  4079.         int sockfd;
  4080.  
  4081.         if(FLAG_IS_SET(new_ufb->ufbflg,UFB_IS_SOCKET))
  4082.         {
  4083.             CloseSocket(new_ufb->ufbfh);
  4084.             sockfd = Dup2Socket(old_ufb->ufbfh,new_ufb->ufbfh);
  4085.         }
  4086.         else
  4087.         {
  4088.             if(SaveDescriptor(new_ufb))
  4089.             {
  4090.                 sockfd = Dup2Socket(old_ufb->ufbfh,-1);
  4091.             }
  4092.             else
  4093.             {
  4094.                 sockfd = -1;
  4095.                 errno = ENOMEM;
  4096.             }
  4097.         }
  4098.  
  4099.         if(sockfd != -1)
  4100.         {
  4101.             SET_FLAG(new_ufb->ufbflg,UFB_IS_SOCKET);
  4102.             new_ufb->ufbfh = sockfd;
  4103.  
  4104.             result = new_fd;
  4105.         }
  4106.     }
  4107.     else
  4108.     {
  4109.         errno = ENOTSOCK;
  4110.     }
  4111.  
  4112.     RETURN(result);
  4113.     return(result);
  4114. }
  4115.  
  4116. /******************************************************************************/
  4117.  
  4118. int
  4119. amiga_chown(char *name,uid_t uid,gid_t gid)
  4120. {
  4121.     struct MangleInfo mi;
  4122.     int result = ERROR;
  4123.  
  4124.     chkabort();
  4125.  
  4126.     ASSERT(name != NULL);
  4127.  
  4128.     ENTER();
  4129.     SHOWSTRING(name);
  4130.     SHOWVALUE(uid);
  4131.     SHOWVALUE(gid);
  4132.  
  4133.     if(MangleName(&name,&mi) == OK)
  4134.     {
  4135.         /* AmigaDOS 3.0 and up have a SetOwner() call. */
  4136.         if(DOSBase->lib_Version >= 39)
  4137.         {
  4138.             if(SetOwner(name,(((LONG)uid) << 16) | gid))
  4139.                 result = OK;
  4140.             else
  4141.                 MapIoErrToErrno();
  4142.         }
  4143.         else
  4144.         {
  4145.             struct DevProc * dvp;
  4146.  
  4147.             /* For 2.04 and 2.1 we'll have to do this
  4148.              * manually...
  4149.              */
  4150.             dvp = GetDeviceProc(name,NULL);
  4151.             if(dvp != NULL)
  4152.             {
  4153.                 char __aligned newName[MAX_BSTR_LEN];
  4154.  
  4155.                 newName[0] = strlen(name);
  4156.                 strncpy(&newName[1],name,newName[0]);
  4157.  
  4158.                 /* This is almost identical in operation to ACTION_SET_PROTECTION. */
  4159.                 if(DoPkt(dvp->dvp_Port,ACTION_SET_OWNER,dvp->dvp_Lock,MKBADDR(newName),(((LONG)uid) << 16) | gid,0,0))
  4160.                     result = OK;
  4161.                 else
  4162.                     MapIoErrToErrno();
  4163.  
  4164.                 FreeDeviceProc(dvp);
  4165.             }
  4166.             else
  4167.             {
  4168.                 MapIoErrToErrno();
  4169.             }
  4170.         }
  4171.  
  4172.         UnmangleName(&name,&mi);
  4173.     }
  4174.  
  4175.     RETURN(result);
  4176.     return(result);
  4177. }
  4178.  
  4179. /******************************************************************************/
  4180.  
  4181. int
  4182. amiga_setegid(gid_t g)
  4183. {
  4184.     int result;
  4185.  
  4186.     chkabort();
  4187.  
  4188.     ENTER();
  4189.     SHOWVALUE(g);
  4190.  
  4191.     result = setregid(-1,g);
  4192.  
  4193.     RETURN(result);
  4194.     return(result);
  4195. }
  4196.  
  4197. /******************************************************************************/
  4198.  
  4199. int
  4200. amiga_seteuid(uid_t u)
  4201. {
  4202.     int result;
  4203.  
  4204.     chkabort();
  4205.  
  4206.     ENTER();
  4207.     SHOWVALUE(u);
  4208.     result = setreuid(-1,u);
  4209.  
  4210.     RETURN(result);
  4211.     return(result);
  4212. }
  4213.  
  4214. /******************************************************************************/
  4215.  
  4216. int
  4217. amiga_gettimeofday(struct timeval *tv)
  4218. {
  4219.     chkabort();
  4220.  
  4221.     ENTER();
  4222.     SHOWVALUE(tv);
  4223.  
  4224.     if(tv != NULL)
  4225.     {
  4226.         GetSysTime((APTR)tv);
  4227.         tv->tv_secs += UNIX_TIME_OFFSET + 60*MinutesWest;    /* translate from local time to UTC */
  4228.  
  4229.         SHOWVALUE(tv->tv_secs);
  4230.         SHOWVALUE(tv->tv_micro);
  4231.     }
  4232.  
  4233.     RETURN(0);
  4234.     return(0);
  4235. }
  4236.  
  4237. /******************************************************************************/
  4238.  
  4239. int
  4240. amiga_utime(char *name,struct utimbuf *time)
  4241. {
  4242.     struct MangleInfo mi;
  4243.     struct DateStamp ds;
  4244.     int result = ERROR;
  4245.  
  4246.     chkabort();
  4247.  
  4248.     ASSERT(name != NULL);
  4249.  
  4250.     ENTER();
  4251.     SHOWSTRING(name);
  4252.     SHOWVALUE(time);
  4253.  
  4254.     /* Use the current time? */
  4255.     if(time == NULL)
  4256.     {
  4257.         DateStamp(&ds);
  4258.     }
  4259.     else
  4260.     {
  4261.         ULONG seconds;
  4262.  
  4263.         /* Convert the time given. */
  4264.         if(time->modtime < (UNIX_TIME_OFFSET + 60*MinutesWest))
  4265.             seconds = 0;
  4266.         else
  4267.             seconds = time->modtime - (UNIX_TIME_OFFSET + 60*MinutesWest);    /* translate from UTC to local time */
  4268.  
  4269.         ds.ds_Days        = (seconds / (24*60*60));
  4270.         ds.ds_Minute    = (seconds % (24*60*60)) / 60;
  4271.         ds.ds_Tick        = (seconds               % 60) * TICKS_PER_SECOND;
  4272.     }
  4273.  
  4274.     if(MangleName(&name,&mi) == OK)
  4275.     {
  4276.         ForbidDOS();
  4277.  
  4278.         if(SetFileDate((STRPTR)name,&ds))
  4279.         {
  4280.             result = OK;
  4281.         }
  4282.         else
  4283.         {
  4284.             LONG error = IoErr();
  4285.  
  4286.             /* Note sure about this one; is it really that important
  4287.              * that the file date change succeeds? This is a definite
  4288.              * FIXME.
  4289.              */
  4290.             if(error == ERROR_OBJECT_IN_USE)
  4291.             {
  4292.                 result = OK;
  4293.             }
  4294.             else
  4295.             {
  4296.                 SetIoErr(error);
  4297.  
  4298.                 MapIoErrToErrno();
  4299.             }
  4300.         }
  4301.  
  4302.         PermitDOS();
  4303.  
  4304.         UnmangleName(&name,&mi);
  4305.     }
  4306.  
  4307.     RETURN(result);
  4308.     return(result);
  4309. }
  4310.  
  4311. /******************************************************************************/
  4312.  
  4313. VOID
  4314. amiga_sleep(unsigned int seconds)
  4315. {
  4316.     chkabort();
  4317.  
  4318.     ENTER();
  4319.     SHOWVALUE(seconds);
  4320.  
  4321.     if(seconds > 0)
  4322.     {
  4323.         ULONG timerSignal = (1UL << TimerPort->mp_SigBit);
  4324.         ULONG signalsReceived;
  4325.         ULONG signalsToWaitFor;
  4326.  
  4327.         TimerRequest->tr_node.io_Command    = TR_ADDREQUEST;
  4328.         TimerRequest->tr_time.tv_secs        = seconds;
  4329.         TimerRequest->tr_time.tv_micro        = 0;
  4330.  
  4331.         SetSignal(0,timerSignal);
  4332.         SendIO((struct IORequest *)TimerRequest);
  4333.  
  4334.         signalsToWaitFor = timerSignal;
  4335.         if(AllowBreak)
  4336.             signalsToWaitFor |= SIGBREAKF_CTRL_C;
  4337.  
  4338.         signalsReceived = Wait(signalsToWaitFor);
  4339.  
  4340.         /* Did we get a break signal while we were sleeping? */
  4341.         if(FLAG_IS_SET(signalsReceived,SIGBREAKF_CTRL_C))
  4342.         {
  4343.             if(CheckIO((struct IORequest *)TimerRequest) == BUSY)
  4344.                 AbortIO((struct IORequest *)TimerRequest);
  4345.  
  4346.             WaitIO((struct IORequest *)TimerRequest);
  4347.  
  4348.             /* And pull the brakes... */
  4349.             raise(SIGINT);
  4350.         }
  4351.  
  4352.         /* Proper termination. */
  4353.         if(FLAG_IS_SET(signalsReceived,timerSignal))
  4354.         {
  4355.             WaitIO((struct IORequest *)TimerRequest);
  4356.         }
  4357.     }
  4358.  
  4359.     LEAVE();
  4360. }
  4361.  
  4362. /******************************************************************************/
  4363.  
  4364. char *
  4365. amiga_crypt(char *key,char *salt)
  4366. {
  4367.     char *result;
  4368.  
  4369.     chkabort();
  4370.  
  4371.     ASSERT(key != NULL && salt != NULL);
  4372.  
  4373.     ENTER();
  4374.     SHOWSTRING(key);
  4375.     SHOWVALUE(salt);
  4376.     result = crypt(key,salt);
  4377.  
  4378.     RETURN(result);
  4379.     return(result);
  4380. }
  4381.  
  4382. /******************************************************************************/
  4383.  
  4384. char *
  4385. amiga_getpass(char *prompt)
  4386. {
  4387.     char *result;
  4388.  
  4389.     chkabort();
  4390.  
  4391.     ENTER();
  4392.     SHOWSTRING(prompt);
  4393.     result = getpass(prompt);
  4394.  
  4395.     RETURN(result);
  4396.     return(result);
  4397. }
  4398.  
  4399. /******************************************************************************/
  4400.  
  4401. int
  4402. amiga_setgid(gid_t id)
  4403. {
  4404.     int result;
  4405.  
  4406.     chkabort();
  4407.  
  4408.     ENTER();
  4409.     SHOWVALUE(id);
  4410.     result = setgid(id);
  4411.  
  4412.     RETURN(result);
  4413.     return(result);
  4414. }
  4415.  
  4416. /******************************************************************************/
  4417.  
  4418. int
  4419. amiga_setgroups(int ngroups,gid_t *groups)
  4420. {
  4421.     int result;
  4422.  
  4423.     chkabort();
  4424.  
  4425.     ASSERT(groups != NULL);
  4426.  
  4427.     ENTER();
  4428.     SHOWVALUE(ngroups);
  4429.     SHOWVALUE(groups);
  4430.  
  4431.     result = setgroups(ngroups,groups);
  4432.  
  4433.     RETURN(result);
  4434.     return(result);
  4435. }
  4436.  
  4437. /******************************************************************************/
  4438.  
  4439. gid_t
  4440. amiga_getgid(VOID)
  4441. {
  4442.     int result;
  4443.  
  4444.     chkabort();
  4445.  
  4446.     ENTER();
  4447.     result = getgid();
  4448.  
  4449.     RETURN(result);
  4450.     return(result);
  4451. }
  4452.  
  4453. /******************************************************************************/
  4454.  
  4455. struct group *
  4456. amiga_getgrgid(gid_t gid)
  4457. {
  4458.     struct group *result;
  4459.  
  4460.     chkabort();
  4461.  
  4462.     ENTER();
  4463.     SHOWVALUE(gid);
  4464.  
  4465.     result = getgrgid(gid);
  4466.  
  4467.     RETURN(result);
  4468.     return(result);
  4469. }
  4470.  
  4471. /******************************************************************************/
  4472.  
  4473. struct group *
  4474. amiga_getgrnam(char * name)
  4475. {
  4476.     struct group *result;
  4477.  
  4478.     chkabort();
  4479.  
  4480.     ASSERT(name != NULL);
  4481.  
  4482.     ENTER();
  4483.     SHOWSTRING(name);
  4484.  
  4485.     result = getgrnam(name);
  4486.  
  4487.     RETURN(result);
  4488.     return(result);
  4489. }
  4490.  
  4491. /******************************************************************************/
  4492.  
  4493. int
  4494. amiga_getgroups(int ngroups, gid_t *groups)
  4495. {
  4496.     int result;
  4497.  
  4498.     chkabort();
  4499.  
  4500.     ASSERT(groups != NULL);
  4501.  
  4502.     ENTER();
  4503.     SHOWVALUE(ngroups);
  4504.     SHOWVALUE(groups);
  4505.  
  4506.     result = getgroups(ngroups,groups);
  4507.  
  4508.     RETURN(result);
  4509.     return(result);
  4510. }
  4511.  
  4512. /******************************************************************************/
  4513.  
  4514. struct hostent *
  4515. amiga_gethostbyaddr(char *addr, int len, int type)
  4516. {
  4517.     struct hostent *result;
  4518.  
  4519.     chkabort();
  4520.  
  4521.     ASSERT(addr != NULL);
  4522.  
  4523.     ENTER();
  4524.     SHOWVALUE(addr);
  4525.     SHOWVALUE(len);
  4526.     SHOWVALUE(type);
  4527.  
  4528.     result = gethostbyaddr(addr,len,type);
  4529.  
  4530.     RETURN(result);
  4531.     return(result);
  4532. }
  4533.  
  4534. /******************************************************************************/
  4535.  
  4536. struct hostent *
  4537. amiga_gethostbyname(char *name)
  4538. {
  4539.     struct hostent *result;
  4540.  
  4541.     chkabort();
  4542.  
  4543.     ASSERT(name != NULL);
  4544.  
  4545.     ENTER();
  4546.     SHOWSTRING(name);
  4547.  
  4548.     result = gethostbyname(name);
  4549.  
  4550.     RETURN(result);
  4551.     return(result);
  4552. }
  4553.  
  4554. /******************************************************************************/
  4555.  
  4556. struct netent *
  4557. amiga_getnetbyname(char *name)
  4558. {
  4559.     struct netent *result;
  4560.  
  4561.     chkabort();
  4562.  
  4563.     ASSERT(name != NULL);
  4564.  
  4565.     ENTER();
  4566.     SHOWSTRING(name);
  4567.  
  4568.     result = getnetbyname(name);
  4569.  
  4570.     RETURN(result);
  4571.     return(result);
  4572. }
  4573.  
  4574. /******************************************************************************/
  4575.  
  4576. int
  4577. amiga_gethostname(char *hostname,int size)
  4578. {
  4579.     int result;
  4580.  
  4581.     chkabort();
  4582.  
  4583.     ASSERT(hostname != NULL);
  4584.  
  4585.     ENTER();
  4586.     SHOWVALUE(hostname);
  4587.     SHOWVALUE(size);
  4588.  
  4589.     result = gethostname(hostname,size);
  4590.  
  4591.     if(result == 0)
  4592.         SHOWSTRING(hostname);
  4593.  
  4594.     RETURN(result);
  4595.     return(result);
  4596. }
  4597.  
  4598. /******************************************************************************/
  4599.  
  4600. struct passwd *
  4601. amiga_getpwnam(char *name)
  4602. {
  4603.     struct passwd *result;
  4604.  
  4605.     chkabort();
  4606.  
  4607.     ASSERT(name != NULL);
  4608.  
  4609.     ENTER();
  4610.     SHOWSTRING(name);
  4611.  
  4612.     result = getpwnam(name);
  4613.  
  4614.     RETURN(result);
  4615.     return(result);
  4616. }
  4617.  
  4618. /******************************************************************************/
  4619.  
  4620. struct passwd *
  4621. amiga_getpwuid(uid_t uid)
  4622. {
  4623.     struct passwd *result;
  4624.  
  4625.     chkabort();
  4626.  
  4627.     ENTER();
  4628.     SHOWVALUE(uid);
  4629.  
  4630.     result = getpwuid(uid);
  4631.  
  4632.     RETURN(result);
  4633.     return(result);
  4634. }
  4635.  
  4636. /******************************************************************************/
  4637.  
  4638. uid_t
  4639. amiga_getuid(VOID)
  4640. {
  4641.     uid_t result;
  4642.  
  4643.     chkabort();
  4644.  
  4645.     ENTER();
  4646.  
  4647.     result = getuid();
  4648.  
  4649.     RETURN(result);
  4650.     return(result);
  4651. }
  4652.  
  4653. /******************************************************************************/
  4654.  
  4655. gid_t
  4656. amiga_getegid(VOID)
  4657. {
  4658.     gid_t result;
  4659.  
  4660.     chkabort();
  4661.  
  4662.     ENTER();
  4663.     result = getegid();
  4664.  
  4665.     RETURN(result);
  4666.     return(result);
  4667. }
  4668.  
  4669. /******************************************************************************/
  4670.  
  4671. uid_t
  4672. amiga_geteuid(VOID)
  4673. {
  4674.     uid_t result;
  4675.  
  4676.     chkabort();
  4677.  
  4678.     ENTER();
  4679.  
  4680.     result = geteuid();
  4681.  
  4682.     RETURN(result);
  4683.     return(result);
  4684. }
  4685.  
  4686. /******************************************************************************/
  4687.  
  4688. int
  4689. amiga_initgroups(char *name, gid_t basegroup)
  4690. {
  4691.     int result;
  4692.  
  4693.     chkabort();
  4694.  
  4695.     ASSERT(name != NULL);
  4696.  
  4697.     ENTER();
  4698.     SHOWSTRING(name);
  4699.     SHOWVALUE(basegroup);
  4700.  
  4701.     result = initgroups(name,basegroup);
  4702.  
  4703.     RETURN(result);
  4704.     return(result);
  4705. }
  4706.  
  4707. /******************************************************************************/
  4708.  
  4709. int
  4710. amiga_setuid(uid_t id)
  4711. {
  4712.     int result;
  4713.  
  4714.     chkabort();
  4715.  
  4716.     ENTER();
  4717.     SHOWVALUE(id);
  4718.  
  4719.     result = setuid(id);
  4720.  
  4721.     RETURN(result);
  4722.     return(result);
  4723. }
  4724.  
  4725. /******************************************************************************/
  4726.  
  4727. int
  4728. amiga_umask(int mask)
  4729. {
  4730.     int result;
  4731.  
  4732.     chkabort();
  4733.  
  4734.     ENTER();
  4735.     SHOWVALUE(mask);
  4736.  
  4737.     result = umask(mask);
  4738.  
  4739.     RETURN(result);
  4740.     return(result);
  4741. }
  4742.  
  4743. /******************************************************************************/
  4744.  
  4745. unsigned long
  4746. amiga_inet_addr(char *addr)
  4747. {
  4748.     unsigned long result;
  4749.  
  4750.     chkabort();
  4751.  
  4752.     ASSERT(addr != NULL);
  4753.  
  4754.     ENTER();
  4755.     SHOWSTRING(addr);
  4756.  
  4757.     result = inet_addr(addr);
  4758.  
  4759.     RETURN(result);
  4760.     return(result);
  4761. }
  4762.  
  4763. /******************************************************************************/
  4764.  
  4765. char *
  4766. amiga_inet_ntoa(struct in_addr in)
  4767. {
  4768.     char *result;
  4769.  
  4770.     chkabort();
  4771.  
  4772.     ENTER();
  4773.     SHOWVALUE(in.s_addr);
  4774.  
  4775.     result = Inet_NtoA(in.s_addr);
  4776.     SHOWSTRING(result);
  4777.  
  4778.     RETURN(result);
  4779.     return(result);
  4780. }
  4781.  
  4782. /******************************************************************************/
  4783.  
  4784. int    opterr = 1;
  4785. int    optind = 1;
  4786. int    optopt;
  4787. char * optarg;
  4788.  
  4789. int
  4790. amiga_getopt(int argc, char * argv[], char *opts)
  4791. {
  4792.     STATIC int sp = 1;
  4793.     int c;
  4794.     char *cp;
  4795.  
  4796.     ASSERT(argc > 0 && argv != NULL && opts != NULL);
  4797.  
  4798.     if(sp == 1)
  4799.     {
  4800.         if(optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
  4801.         {
  4802.             return(EOF);
  4803.         }
  4804.         else if(strcmp(argv[optind], "--") == NULL)
  4805.         {
  4806.             optind++;
  4807.             return(EOF);
  4808.         }
  4809.     }
  4810.  
  4811.     optopt = c = argv[optind][sp];
  4812.     if(c == ':' || (cp=index(opts, c)) == NULL)
  4813.     {
  4814.         if(opterr)
  4815.             fprintf(stderr, "%s%s%c\n", argv[0], ": illegal option -- ", c);
  4816.  
  4817.         if(argv[optind][++sp] == '\0')
  4818.         {
  4819.             optind++;
  4820.             sp = 1;
  4821.         }
  4822.  
  4823.         return('?');
  4824.     }
  4825.  
  4826.     if(*++cp == ':')
  4827.     {
  4828.         if(argv[optind][sp+1] != '\0')
  4829.         {
  4830.             optarg = &argv[optind++][sp+1];
  4831.         }
  4832.         else if(++optind >= argc)
  4833.         {
  4834.             if(opterr)
  4835.                 fprintf(stderr, "%s%s%c\n", argv[0], ": option requires an argument -- ", c);
  4836.  
  4837.             sp = 1;
  4838.             return('?');
  4839.         }
  4840.         else
  4841.         {
  4842.             optarg = argv[optind++];
  4843.         }
  4844.  
  4845.         sp = 1;
  4846.     }
  4847.     else
  4848.     {
  4849.         if(argv[optind][++sp] == '\0')
  4850.         {
  4851.             sp = 1;
  4852.             optind++;
  4853.         }
  4854.  
  4855.         optarg = NULL;
  4856.     }
  4857.  
  4858.     return(c);
  4859. }
  4860.  
  4861. /******************************************************************************/
  4862.  
  4863. /* This comes from util/lib.c */
  4864. STATIC BOOL
  4865. do_match(STRPTR str, STRPTR regexp)
  4866. {
  4867.     STRPTR p;
  4868.  
  4869.     for(p = regexp; (*p) != '\0' && (*str) != '\0' ; NULL)
  4870.     {
  4871.         switch(*p)
  4872.         {
  4873.             case '?':
  4874.  
  4875.                 str++;
  4876.                 p++;
  4877.  
  4878.                 break;
  4879.  
  4880.             /* Look for a character matching the one after the '*' */
  4881.             case '*':
  4882.  
  4883.                 p++;
  4884.  
  4885.                 if((*p) == '\0')
  4886.                     return(TRUE); /* Automatic match */
  4887.  
  4888.                 while((*str) != '\0')
  4889.                 {
  4890.                     while((*str) != '\0' && ToUpper(*p) != ToUpper(*str))
  4891.                         str++;
  4892.  
  4893.                     if(do_match(str,p))
  4894.                         return(TRUE);
  4895.  
  4896.                     if((*str) == '\0')
  4897.                         return(FALSE);
  4898.                     else
  4899.                         str++;
  4900.                 }
  4901.  
  4902.                 return(FALSE);
  4903.  
  4904.             default:
  4905.  
  4906.                 if(ToUpper(*str++) != ToUpper(*p++))
  4907.                     return(FALSE);
  4908.  
  4909.                 break;
  4910.         }
  4911.     }
  4912.  
  4913.     if((*p) == '\0' && (*str) == '\0')
  4914.         return(TRUE);
  4915.  
  4916.     if((*p) == '\0' && str[0] == '.' && str[1] == '\0')
  4917.         return(TRUE);
  4918.  
  4919.     if((*str) == '\0' && (*p) == '?')
  4920.     {
  4921.         while((*p) == '?')
  4922.             p++;
  4923.  
  4924.         return((BOOL)((*p) == '\0'));
  4925.     }
  4926.  
  4927.     if((*str) == '\0' && ((*p) == '*' && p[1] == '\0'))
  4928.         return(TRUE);
  4929.  
  4930.     return(FALSE);
  4931. }
  4932.  
  4933. STATIC VOID
  4934. nstrcpy_blank(const size_t maxSize,char *to,const char *from)
  4935. {
  4936.     size_t len = 0;
  4937.  
  4938.     while((*from) != '\0' && (*from) != ' ' && len < maxSize-1)
  4939.     {
  4940.         (*to++) = (*from++);
  4941.         len++;
  4942.     }
  4943.  
  4944.     (*to) = '\0';
  4945. }
  4946.  
  4947. STATIC VOID
  4948. fill_volume_list(struct List * list)
  4949. {
  4950.     struct DosList * dol;
  4951.  
  4952.     dol = NextDosEntry(LockDosList(LDF_VOLUMES|LDF_READ),
  4953.                                    LDF_VOLUMES|LDF_READ);
  4954.     while(dol != NULL)
  4955.     {
  4956.         /* Does the volume refer to a medium that is right
  4957.          * now present in the drive?
  4958.          */
  4959.         if(dol->dol_Task != NULL)
  4960.         {
  4961.             struct InfoData __aligned id;
  4962.  
  4963.             /* Is there a disk present? */
  4964.             if(DoPkt(dol->dol_Task,ACTION_DISK_INFO,MKBADDR(&id),    0,0,0,0))
  4965.             {
  4966.                 STRPTR name = BADDR(dol->dol_Name);
  4967.                 struct Node * node;
  4968.  
  4969.                 node = malloc(sizeof(*node) + ((int)name[0])+1);
  4970.                 if(node != NULL)
  4971.                 {
  4972.                     /* Copy the name of the volume. */
  4973.                     node->ln_Name = (char *)(node + 1);
  4974.                     strncpy(node->ln_Name,&name[1],name[0]);
  4975.                     node->ln_Name[ name[0] ] = '\0';
  4976.  
  4977.                     AddTail(list,node);
  4978.                 }
  4979.             }
  4980.         }
  4981.  
  4982.         dol = NextDosEntry(dol,LDF_VOLUMES|LDF_READ);
  4983.     }
  4984.  
  4985.     UnLockDosList(LDF_VOLUMES|LDF_READ);
  4986. }
  4987.  
  4988. STATIC int
  4989. deep_scan_drawer(char * drawerName,char * whichPattern,FILE * out)
  4990. {
  4991.     char * originalDrawerName;
  4992.     struct MangleInfo mi;
  4993.     int result = ERROR;
  4994.  
  4995.     originalDrawerName = drawerName;
  4996.     if(MangleName(&drawerName,&mi) == OK)
  4997.     {
  4998.         BPTR dirLock;
  4999.  
  5000.         dirLock = Lock(drawerName,SHARED_LOCK);
  5001.         if(dirLock != ZERO)
  5002.         {
  5003.             struct FileInfoBlock __aligned fib;
  5004.  
  5005.             if(Examine(dirLock,&fib))
  5006.             {
  5007.                 struct AnchorPath * ap;
  5008.  
  5009.                 ap = malloc(sizeof(*ap) + MAX_FILENAME_LEN);
  5010.                 if(ap != NULL)
  5011.                 {
  5012.                     BOOL stopped = FALSE;
  5013.                     BPTR oldDir;
  5014.                     LONG error;
  5015.  
  5016.                     oldDir = CurrentDir(dirLock);
  5017.  
  5018.                     memset(ap,0,sizeof(*ap) + MAX_FILENAME_LEN);
  5019.                     ap->ap_Strlen        = MAX_FILENAME_LEN;
  5020.                     ap->ap_BreakBits    = SIGBREAKF_CTRL_C;
  5021.  
  5022.                     if((error = MatchFirst("",ap)) == OK)
  5023.                     {
  5024.                         BOOL check;
  5025.  
  5026.                         do
  5027.                         {
  5028.                             D(("checking |%s|",ap->ap_Buf));
  5029.  
  5030.                             check = TRUE;
  5031.  
  5032.                             if(FIB_IS_FILE(&ap->ap_Info))
  5033.                             {
  5034.                                 SHOWMSG("this is a file");
  5035.                             }
  5036.                             else
  5037.                             {
  5038.                                 SHOWMSG("this is a drawer");
  5039.  
  5040.                                 if(FLAG_IS_CLEAR(ap->ap_Flags,APF_DIDDIR))
  5041.                                 {
  5042.                                     SET_FLAG(ap->ap_Flags,APF_DODIR);
  5043.                                 }
  5044.                                 else
  5045.                                 {
  5046.                                     CLEAR_FLAG(ap->ap_Flags,APF_DIDDIR);
  5047.                                     check = FALSE;
  5048.                                 }
  5049.                             }
  5050.  
  5051.                             if(check)
  5052.                             {
  5053.                                 SHOWSTRING(ap->ap_Info.fib_FileName);
  5054.  
  5055.                                 if(do_match(ap->ap_Info.fib_FileName,whichPattern))
  5056.                                 {
  5057.                                     D(("Output |%s/%s|",originalDrawerName,ap->ap_Buf));
  5058.                                     if(fprintf(out,"%s/%s\n",originalDrawerName,ap->ap_Buf) < 0)
  5059.                                     {
  5060.                                         stopped = TRUE;
  5061.                                         break;
  5062.                                     }
  5063.                                 }
  5064.                                 else
  5065.                                 {
  5066.                                     SHOWMSG("but its name does not match");
  5067.                                 }
  5068.                             }
  5069.                         }
  5070.                         while((error = MatchNext(ap)) == OK);
  5071.                     }
  5072.  
  5073.                     MatchEnd(ap);
  5074.  
  5075.                     CurrentDir(oldDir);
  5076.  
  5077.                     if(NOT stopped)
  5078.                     {
  5079.                         if(error == ERROR_NO_MORE_ENTRIES)
  5080.                         {
  5081.                             result = OK;
  5082.                         }
  5083.                         else if(error == ERROR_BREAK)
  5084.                         {
  5085.                             /* Don't do anything; we are going
  5086.                              * to delete the file anyway.
  5087.                              */
  5088.                         }
  5089.                         else
  5090.                         {
  5091.                             SetIoErr(error);
  5092.                             MapIoErrToErrno();
  5093.                         }
  5094.                     }
  5095.  
  5096.                     free(ap);
  5097.                 }
  5098.                 else
  5099.                 {
  5100.                     errno = ENOMEM;
  5101.                 }
  5102.             }
  5103.             else
  5104.             {
  5105.                 MapIoErrToErrno();
  5106.             }
  5107.  
  5108.             UnLock(dirLock);
  5109.         }
  5110.         else
  5111.         {
  5112.             MapIoErrToErrno();
  5113.         }
  5114.  
  5115.         UnmangleName(&drawerName,&mi);
  5116.     }
  5117.  
  5118.     return(result);
  5119. }
  5120.  
  5121. int
  5122. amiga_system(char *cmd)
  5123. {
  5124.     char redirectionFileBuffer[MAX_FILENAME_LEN];
  5125.     char *redirectionFile = redirectionFileBuffer;
  5126.     struct MangleInfo mi;
  5127.     int result = ERROR;
  5128.     char *stop;
  5129.     char *options;
  5130.     char *cmdName;
  5131.     int cmdLen,i;
  5132.     int quoteCount;
  5133.  
  5134.     chkabort();
  5135.  
  5136.     ASSERT(cmd != NULL);
  5137.  
  5138.     ENTER();
  5139.     SHOWSTRING(cmd);
  5140.  
  5141.     /* Handle two special cases for the smb client program,
  5142.      * which for reasons unknown to me resorts to calling
  5143.      * the Unix "ls" and "find" programs to collect lists
  5144.      * of files.
  5145.      *
  5146.      * The commands to watch for take the following forms:
  5147.      *
  5148.      *    /bin/ls file_to_list > output_filename
  5149.      *    find directory_to_list -name "pattern_to_list" -print > output_filename
  5150.      */
  5151.     stop = cmd;
  5152.     while((*stop) != ' ' && (*stop) != '\0')
  5153.         stop++;
  5154.  
  5155.     /* This will point behind the command name,
  5156.      * to the beginning of the list of options,
  5157.      * if any.
  5158.      */
  5159.     options = stop;
  5160.     while((*options) == ' ')
  5161.         options++;
  5162.  
  5163.     /* Now go and isolate the command name. */
  5164.     cmdName = cmd;
  5165.     cmdLen = stop-cmd;
  5166.     for(i = cmdLen - 1 ; i >= 0 ; i--)
  5167.     {
  5168.         if(cmd[i] == '/' || cmd[i] == ':')
  5169.         {
  5170.             cmdName = &cmd[i+1];
  5171.  
  5172.             stop = cmdName;
  5173.             while((*stop) != ' ' && (*stop) != '\0')
  5174.                 stop++;
  5175.  
  5176.             cmdLen = stop-cmdName;
  5177.  
  5178.             break;
  5179.         }
  5180.     }
  5181.  
  5182.     /* We have isolated the command name, now
  5183.      * find the redirection file name.
  5184.      */
  5185.     quoteCount = 0;
  5186.     strcpy(redirectionFile,"");
  5187.     for(i = 0 ; i < strlen(cmd) ; i++)
  5188.     {
  5189.         if(cmd[i] == '\"')
  5190.             quoteCount = (1-quoteCount);
  5191.  
  5192.         if(cmd[i] == '>' && quoteCount == 0)
  5193.         {
  5194.             char * from;
  5195.  
  5196.             from = &cmd[i+1];
  5197.             while((*from) == ' ')
  5198.                 from++;
  5199.  
  5200.             /* Note that we rely upon the
  5201.              * redirection file name not to contain
  5202.              * quote or escape characters.
  5203.              */
  5204.             nstrcpy_blank(sizeof(redirectionFileBuffer),redirectionFile,from);
  5205.             break;
  5206.         }
  5207.     }
  5208.  
  5209.     /* Now check which command we got. */
  5210.     if(cmdLen == 2 && Strnicmp(cmdName,"ls",2) == SAME)
  5211.     {
  5212.         char localDirName[MAX_FILENAME_LEN];
  5213.         char * dirName;
  5214.  
  5215.         dirName = ".";
  5216.  
  5217.         if(TranslateRelativePath(&dirName,localDirName,sizeof(localDirName)) == OK)
  5218.         {
  5219.             char whichPatternBuffer[MAX_FILENAME_LEN];
  5220.             char *whichPattern = whichPatternBuffer;
  5221.             BOOL oldAllowBreak = AllowBreak;
  5222.  
  5223.             /* We don't want to be interrupted. */
  5224.             AllowBreak = FALSE;
  5225.  
  5226.             /* Now find the pattern to use. */
  5227.             nstrcpy_blank(sizeof(whichPatternBuffer),whichPattern,options);
  5228.  
  5229.             SHOWMSG("doing `ls'");
  5230.             SHOWSTRING(whichPattern);
  5231.             SHOWSTRING(redirectionFile);
  5232.  
  5233.             /* What happens next is that the contents of the
  5234.              * current directory are scanned. All names
  5235.              * that match the given pattern are stored in the
  5236.              * redirection file.
  5237.              */
  5238.  
  5239.             if(MangleName(&redirectionFile,&mi) == OK)
  5240.             {
  5241.                 FILE * out;
  5242.  
  5243.                 ForbidDOS();
  5244.  
  5245.                 out = fopen(redirectionFile,"wb");
  5246.                 if(out != NULL)
  5247.                 {
  5248.                     SHOWSTRING(localDirName);
  5249.  
  5250.                     if(strcmp(localDirName,"/") == SAME)
  5251.                     {
  5252.                         struct List list;
  5253.                         struct Node * node;
  5254.  
  5255.                         SHOWMSG("listing volumes");
  5256.  
  5257.                         NewList(&list);
  5258.  
  5259.                         fill_volume_list(&list);
  5260.  
  5261.                         while((node = RemHead(&list)) != NULL)
  5262.                         {
  5263.                             D(("checking '%s'",node->ln_Name));
  5264.  
  5265.                             if(do_match(node->ln_Name,whichPattern))
  5266.                             {
  5267.                                 SHOWMSG(">>> matches");
  5268.  
  5269.                                 if(fprintf(out,"%s\n",node->ln_Name) < 0)
  5270.                                     break;
  5271.                             }
  5272.                             else
  5273.                             {
  5274.                                 SHOWMSG(">>> does not match");
  5275.                             }
  5276.  
  5277.                             free(node);
  5278.                         }
  5279.  
  5280.                         while((node = RemHead(&list)) != NULL)
  5281.                             free(node);
  5282.                     }
  5283.                     else
  5284.                     {
  5285.                         BPTR dirLock;
  5286.  
  5287.                         SHOWMSG("listing drawers");
  5288.  
  5289.                         dirLock = Lock("",SHARED_LOCK);
  5290.                         if(dirLock != ZERO)
  5291.                         {
  5292.                             struct FileInfoBlock __aligned fib;
  5293.  
  5294.                             if(Examine(dirLock,&fib))
  5295.                             {
  5296.                                 BOOL stopped = FALSE;
  5297.  
  5298.                                 while(ExNext(dirLock,&fib))
  5299.                                 {
  5300.                                     D(("checking '%s'",fib.fib_FileName));
  5301.  
  5302.                                     if(do_match(fib.fib_FileName,whichPattern))
  5303.                                     {
  5304.                                         SHOWMSG(">>> matches");
  5305.  
  5306.                                         if(fprintf(out,"%s\n",fib.fib_FileName) < 0)
  5307.                                         {
  5308.                                             stopped = TRUE;
  5309.                                             break;
  5310.                                         }
  5311.                                     }
  5312.                                     else
  5313.                                     {
  5314.                                         SHOWMSG(">>> does not match");
  5315.                                     }
  5316.                                 }
  5317.  
  5318.                                 if(NOT stopped)
  5319.                                 {
  5320.                                     LONG error = IoErr();
  5321.  
  5322.                                     if(error == ERROR_NO_MORE_ENTRIES)
  5323.                                     {
  5324.                                         result = OK;
  5325.                                     }
  5326.                                     else
  5327.                                     {
  5328.                                         SetIoErr(error);
  5329.                                         MapIoErrToErrno();
  5330.                                     }
  5331.                                 }
  5332.                             }
  5333.                             else
  5334.                             {
  5335.                                 MapIoErrToErrno();
  5336.                             }
  5337.  
  5338.                             UnLock(dirLock);
  5339.                         }
  5340.                         else
  5341.                         {
  5342.                             MapIoErrToErrno();
  5343.                         }
  5344.                     }
  5345.  
  5346.                     fclose(out);
  5347.  
  5348.                     if(result != OK)
  5349.                         DeleteFile(redirectionFile);
  5350.                 }
  5351.  
  5352.                 PermitDOS();
  5353.  
  5354.                 UnmangleName(&cmd,&mi);
  5355.             }
  5356.  
  5357.             AllowBreak = oldAllowBreak;
  5358.         }
  5359.     }
  5360.     else if (cmdLen == 4 && Strnicmp(cmdName,"find",4) == SAME)
  5361.     {
  5362.         char whichDrawerBuffer[MAX_FILENAME_LEN];
  5363.         char * whichDrawer = whichDrawerBuffer;
  5364.         char whichPattern[MAX_FILENAME_LEN];
  5365.         const int _nameLen = strlen("-name");
  5366.         BOOL oldAllowBreak = AllowBreak;
  5367.         struct List list;
  5368.         struct Node * node;
  5369.  
  5370.         NewList(&list);
  5371.  
  5372.         /* We don't want to be interrupted. */
  5373.         AllowBreak = FALSE;
  5374.  
  5375.         /* Now find the drawer to examine. */
  5376.         nstrcpy_blank(sizeof(whichDrawerBuffer),whichDrawer,options);
  5377.  
  5378.         /* Find the pattern to search for. */
  5379.         strcpy(whichPattern,"");
  5380.         for(i = 0 ; i < strlen(options) ; i++)
  5381.         {
  5382.             if(Strnicmp(&options[i],"-name",_nameLen) == SAME)
  5383.             {
  5384.                 const int maxLen = sizeof(whichPattern)-1;
  5385.                 int whichPatternLen;
  5386.                 int escapeCount;
  5387.                 int quoteCount;
  5388.                 char * from;
  5389.                 char * to;
  5390.  
  5391.                 /* `from' should now point straight at the
  5392.                  * search pattern, which is probably enclosed
  5393.                  * in quote characters.
  5394.                  */
  5395.                 from = &options[i+_nameLen];
  5396.                 while((*from) == ' ')
  5397.                     from++;
  5398.  
  5399.                 to = whichPattern;
  5400.                 whichPatternLen = 0;
  5401.                 quoteCount = 0;
  5402.                 escapeCount = 0;
  5403.                 while((*from) != '\0' && whichPatternLen < maxLen)
  5404.                 {
  5405.                     if(escapeCount != 0)
  5406.                     {
  5407.                         (*to++) = (*from++);
  5408.                         whichPatternLen++;
  5409.                         escapeCount = 0;
  5410.                     }
  5411.                     else if((*from) == '\\')
  5412.                     {
  5413.                         escapeCount = (1-escapeCount);
  5414.                         from++;
  5415.                     }
  5416.                     else if ((*from) == '\"')
  5417.                     {
  5418.                         quoteCount = (1-quoteCount);
  5419.                         from++;
  5420.                     }
  5421.                     else
  5422.                     {
  5423.                         if((*from) == ' ' && quoteCount == 0)
  5424.                         {
  5425.                             break;
  5426.                         }
  5427.                         else
  5428.                         {
  5429.                             (*to++) = (*from++);
  5430.                             whichPatternLen++;
  5431.                         }
  5432.                     }
  5433.                 }
  5434.  
  5435.                 (*to) = '\0';
  5436.             }
  5437.         }
  5438.  
  5439.         SHOWMSG("doing `find'");
  5440.         SHOWSTRING(whichDrawer);
  5441.         SHOWSTRING(whichPattern);
  5442.         SHOWSTRING(redirectionFile);
  5443.  
  5444.         /* Things are a little bit more complicated here. The
  5445.          * "find" program scans recursively through a directory
  5446.          * tree. We emulate this behaviour by having the MatchFirst/MatchNext
  5447.          * routines iterate through the directory tree. The
  5448.          * name of every file found is matched against the given
  5449.          * pattern and, if necessary, written to the redirection
  5450.          * file. Note that matching is performed only on the
  5451.          * file name, not on the entire path.
  5452.          */
  5453.  
  5454.         if(MangleName(&redirectionFile,&mi) == OK)
  5455.         {
  5456.             FILE * out;
  5457.  
  5458.             ForbidDOS();
  5459.  
  5460.             out = fopen(redirectionFile,"wb");
  5461.             if(out != NULL)
  5462.             {
  5463.                 char localDirName[MAX_FILENAME_LEN];
  5464.                 char * dirName;
  5465.  
  5466.                 dirName = whichDrawer;
  5467.  
  5468.                 if(TranslateRelativePath(&dirName,localDirName,sizeof(localDirName)) == OK)
  5469.                 {
  5470.                     D(("listing path '%s'",dirName));
  5471.  
  5472.                     if(strcmp(dirName,"/") == SAME)
  5473.                     {
  5474.                         SHOWMSG("checking all 'drawers' in the fake root");
  5475.  
  5476.                         fill_volume_list(&list);
  5477.  
  5478.                         while((node = RemHead(&list)) != NULL)
  5479.                         {
  5480.                             strcpy(localDirName,"/");
  5481.                             strcat(localDirName,node->ln_Name);
  5482.                             free(node);
  5483.  
  5484.                             D(("checking '%s'",localDirName));
  5485.  
  5486.                             result = deep_scan_drawer(localDirName,whichPattern,out);
  5487.                             if(result != OK)
  5488.                                 break;
  5489.                         }
  5490.  
  5491.                         while((node = RemHead(&list)) != NULL)
  5492.                             free(node);
  5493.                     }
  5494.                     else
  5495.                     {
  5496.                         SHOWMSG("checking only a local drawer");
  5497.  
  5498.                         result = deep_scan_drawer(dirName,whichPattern,out);
  5499.                     }
  5500.                 }
  5501.  
  5502.                 fclose(out);
  5503.  
  5504.                 if(result != OK)
  5505.                     DeleteFile(redirectionFile);
  5506.             }
  5507.  
  5508.             PermitDOS();
  5509.  
  5510.             UnmangleName(&cmd,&mi);
  5511.         }
  5512.  
  5513.         AllowBreak = oldAllowBreak;
  5514.     }
  5515.     else
  5516.     {
  5517.         if(MangleName(&cmd,&mi) == OK)
  5518.         {
  5519.             ForbidDOS();
  5520.             result = system(cmd);
  5521.             PermitDOS();
  5522.  
  5523.             UnmangleName(&cmd,&mi);
  5524.         }
  5525.     }
  5526.  
  5527.     RETURN(result);
  5528.     return(result);
  5529. }
  5530.  
  5531. /******************************************************************************/
  5532.  
  5533. int
  5534. amiga_fork(VOID)    /* dummy */
  5535. {
  5536.     int result;
  5537.  
  5538.     chkabort();
  5539.  
  5540.     ENTER();
  5541.  
  5542.     result = ERROR;
  5543.     errno = ENOSYS;
  5544.  
  5545.     RETURN(result);
  5546.     return(result);
  5547. }
  5548.  
  5549. /******************************************************************************/
  5550.  
  5551. STATIC BOOL
  5552. SetFileSocket(FILE *stream,int sockfd)
  5553. {
  5554.     struct UFB * ufb;
  5555.     BOOL success = FALSE;
  5556.  
  5557.     ASSERT(stream != NULL);
  5558.  
  5559.     ENTER();
  5560.  
  5561.     /* Check which buffer the file
  5562.      * is attached to.
  5563.      */
  5564.     ufb = chkufb(fileno(stream));
  5565.     if(ufb != NULL)
  5566.     {
  5567.         SHOWVALUE(ufb);
  5568.  
  5569.         /* Save the file handle. */
  5570.         if(SaveDescriptor(ufb))
  5571.         {
  5572.             /* And put the socket in its place. */
  5573.             ufb->ufbfh = sockfd;
  5574.             SET_FLAG(ufb->ufbflg,UFB_IS_SOCKET);
  5575.  
  5576.             success = TRUE;
  5577.         }
  5578.     }
  5579.     else
  5580.     {
  5581.         SHOWMSG("no ufb");
  5582.     }
  5583.  
  5584.     RETURN(success);
  5585.     return(success);
  5586. }
  5587.  
  5588. STATIC VOID
  5589. DaemonInit(VOID)
  5590. {
  5591.     struct DaemonMessage * dm;
  5592.     int sock;
  5593.  
  5594.     ENTER();
  5595.  
  5596.     /* This routine is called when the program starts up.
  5597.      * If it was launched by the INet super server, this
  5598.      * program will run as a daemon. We pick up its
  5599.      * socket input stream and attach it to our stdio
  5600.      * streams.
  5601.      */
  5602.     dm = (struct DaemonMessage *)((struct Process *)FindTask(NULL))->pr_ExitData;
  5603.     if(dm != NULL)
  5604.     {
  5605.         sock = ObtainSocket(dm->dm_ID,dm->dm_Family,dm->dm_Type,0);
  5606.         if(sock != -1)
  5607.         {
  5608.             BOOL success = FALSE;
  5609.             int sock_stdin;
  5610.             int sock_stdout;
  5611.             int sock_stderr;
  5612.  
  5613.             sock_stdin    = Dup2Socket(sock,-1);
  5614.             sock_stdout    = Dup2Socket(sock,-1);
  5615.             sock_stderr    = Dup2Socket(sock,-1);
  5616.  
  5617.             if(sock_stdin != -1 && sock_stdout != -1 && sock_stderr != -1)
  5618.             {
  5619.                 SHOWMSG("got all sockets");
  5620.  
  5621.                 D(("stdin  = sock %ld",sock_stdin));
  5622.                 D(("stdout = sock %ld",sock_stdout));
  5623.                 D(("stderr = sock %ld",sock_stderr));
  5624.  
  5625.                 if(SetFileSocket(stdin,sock_stdin) &&
  5626.                    SetFileSocket(stdout,sock_stdout) &&
  5627.                    SetFileSocket(stderr,sock_stderr))
  5628.                 {
  5629.                     SHOWMSG("and all streams are initialized");
  5630.  
  5631.                     success = TRUE;
  5632.                 }
  5633.                 else
  5634.                 {
  5635.                     SHOWMSG("failed to initialize streams");
  5636.                 }
  5637.             }
  5638.             else
  5639.             {
  5640.                 SHOWMSG("didn't get the sockets");
  5641.             }
  5642.  
  5643.             if(NO success)
  5644.             {
  5645.                 if(sock_stdin != -1)
  5646.                     CloseSocket(sock_stdin);
  5647.  
  5648.                 if(sock_stdout != -1)
  5649.                     CloseSocket(sock_stdout);
  5650.  
  5651.                 if(sock_stderr != -1)
  5652.                     CloseSocket(sock_stderr);
  5653.             }
  5654.         }
  5655.         else
  5656.         {
  5657.             SHOWMSG("no socket");
  5658.         }
  5659.     }
  5660.     else
  5661.     {
  5662.         SHOWMSG("No daemon message");
  5663.     }
  5664.  
  5665.     LEAVE();
  5666. }
  5667.  
  5668. /******************************************************************************/
  5669.  
  5670. VOID
  5671. __tzset(VOID)
  5672. {
  5673.     STATIC char TimeZoneName[20] = "";
  5674.  
  5675.     /* This routine sets up the internal
  5676.      * time zone variable according to
  5677.      * the local settings.
  5678.      */
  5679.     if(STRING_IS_EMPTY(TimeZoneName))
  5680.     {
  5681.         int hoursWest = MinutesWest / 60;
  5682.  
  5683.         if(hoursWest >= 0)
  5684.             sprintf(TimeZoneName,"GMT+%02d", hoursWest);
  5685.         else
  5686.             sprintf(TimeZoneName,"GMT-%02d",-hoursWest);
  5687.     }
  5688.  
  5689.     _TZ = TimeZoneName;
  5690. }
  5691.  
  5692. /******************************************************************************/
  5693.  
  5694. time_t
  5695. time(time_t *timeptr)
  5696. {
  5697.     time_t currentTime;
  5698.     struct timeval tv;
  5699.  
  5700.     chkabort();
  5701.  
  5702.     GetSysTime((APTR)&tv);
  5703.  
  5704.     currentTime = UNIX_TIME_OFFSET + tv.tv_secs + 60*MinutesWest;    /* translate from local time to UTC */
  5705.  
  5706.     if(timeptr != NULL)
  5707.         (*timeptr) = currentTime;
  5708.  
  5709.     return(currentTime);
  5710. }
  5711.  
  5712. /******************************************************************************/
  5713.  
  5714. STATIC struct tm *
  5715. ConvertTime(ULONG seconds)
  5716. {
  5717.     STATIC struct tm tm;
  5718.     struct ClockData clockData;
  5719.     ULONG delta;
  5720.  
  5721.     chkabort();
  5722.  
  5723.     Amiga2Date(seconds,&clockData);
  5724.  
  5725.     tm.tm_sec    = clockData.sec;
  5726.     tm.tm_min    = clockData.min;
  5727.     tm.tm_hour    = clockData.hour;
  5728.     tm.tm_mday    = clockData.mday;
  5729.     tm.tm_mon    = clockData.month - 1;
  5730.     tm.tm_year    = clockData.year - 1900;
  5731.     tm.tm_wday    = clockData.wday;
  5732.     tm.tm_isdst    = 0;
  5733.  
  5734.     clockData.mday    = 1;
  5735.     clockData.month    = 1;
  5736.  
  5737.     delta = Date2Amiga(&clockData);
  5738.  
  5739.     tm.tm_yday = (seconds - delta) / (24*60*60);
  5740.  
  5741.     return(&tm);
  5742. }
  5743.  
  5744. struct tm *
  5745. gmtime(const time_t *t)
  5746. {
  5747.     struct tm * result;
  5748.     ULONG seconds;
  5749.  
  5750.     if((*t) < UNIX_TIME_OFFSET)
  5751.         seconds = 0;
  5752.     else
  5753.         seconds = (*t) - UNIX_TIME_OFFSET;
  5754.  
  5755.     result = ConvertTime(seconds);
  5756.  
  5757.     return(result);
  5758. }
  5759.  
  5760. struct tm *
  5761. localtime(const time_t *t)
  5762. {
  5763.     struct tm * result;
  5764.     ULONG seconds;
  5765.  
  5766.     if((*t) < (UNIX_TIME_OFFSET + 60*MinutesWest))
  5767.         seconds = 0;
  5768.     else
  5769.         seconds = (*t) - (UNIX_TIME_OFFSET + 60*MinutesWest);    /* translate from UTC to local time */
  5770.  
  5771.     result = ConvertTime(seconds);
  5772.  
  5773.     return(result);
  5774. }
  5775.  
  5776. /******************************************************************************/
  5777.  
  5778. int
  5779. amiga_strcasecmp(char *a,char *b)
  5780. {
  5781.     int result;
  5782.  
  5783.     ASSERT(a != NULL && b != NULL);
  5784.  
  5785.     result = Stricmp((STRPTR)a,b);
  5786.  
  5787.     return(result);
  5788. }
  5789.  
  5790. int
  5791. amiga_strncasecmp(char *a,char *b,int len)
  5792. {
  5793.     int result;
  5794.  
  5795.     ASSERT(a != NULL && b != NULL);
  5796.  
  5797.     result = Strnicmp(a,b,len);
  5798.  
  5799.     return(result);
  5800. }
  5801.  
  5802. /******************************************************************************/
  5803.  
  5804. VOID
  5805. (*amiga_signal(int which,VOID (* action)(int)))(int)
  5806. {
  5807.     VOID (* result)(int);
  5808.  
  5809.     chkabort();
  5810.  
  5811.     ENTER();
  5812.  
  5813.     if(SIGABRT <= which && which <= SIGTERM)
  5814.         result = signal(which,action);
  5815.     else
  5816.         result = SIG_DFL;
  5817.  
  5818.     RETURN(result);
  5819.     return(result);
  5820. }
  5821.  
  5822. /******************************************************************************/
  5823.  
  5824. VOID
  5825. amiga_alarm(int seconds)    /* dummy */
  5826. {
  5827.     chkabort();
  5828.  
  5829.     ENTER();
  5830.  
  5831.     LEAVE();
  5832. }
  5833.  
  5834. /******************************************************************************/
  5835.  
  5836. int
  5837. amiga_waitpid(pid_t pid,int *status,int options)    /* dummy */
  5838. {
  5839.     int result;
  5840.  
  5841.     chkabort();
  5842.  
  5843.     ENTER();
  5844.  
  5845.     result = ERROR;
  5846.     errno = ENOSYS;
  5847.  
  5848.     RETURN(result);
  5849.     return(result);
  5850. }
  5851.  
  5852. /******************************************************************************/
  5853.  
  5854. long
  5855. amiga_setsid(VOID)
  5856. {
  5857.     long result;
  5858.  
  5859.     chkabort();
  5860.  
  5861.     ENTER();
  5862.  
  5863.     result = (long)setsid();
  5864.  
  5865.     RETURN(result);
  5866.     return(result);
  5867. }
  5868.  
  5869. /******************************************************************************/
  5870.  
  5871. int
  5872. amiga_setreuid(uid_t real, uid_t eff)
  5873. {
  5874.     int result;
  5875.  
  5876.     chkabort();
  5877.  
  5878.     ENTER();
  5879.  
  5880.     result = setreuid(real,eff);
  5881.  
  5882.     RETURN(result);
  5883.     return(result);
  5884. }
  5885.  
  5886. /******************************************************************************/
  5887.  
  5888. int
  5889. amiga_setregid(gid_t real, gid_t eff)
  5890. {
  5891.     int result;
  5892.  
  5893.     chkabort();
  5894.  
  5895.     ENTER();
  5896.  
  5897.     result = setregid(real,eff);
  5898.  
  5899.     RETURN(result);
  5900.     return(result);
  5901. }
  5902.  
  5903. /******************************************************************************/
  5904.  
  5905. int
  5906. amiga_getsockname(int sockfd,struct sockaddr *name,int *namelen)
  5907. {
  5908.     struct UFB * ufb;
  5909.     int result = ERROR;
  5910.  
  5911.     chkabort();
  5912.  
  5913.     ASSERT(name != NULL && namelen != NULL);
  5914.  
  5915.     ENTER();
  5916.  
  5917.     ufb = chkufb(sockfd);
  5918.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  5919.         result = getsockname(ufb->ufbfh,name,(LONG *)namelen);
  5920.     else
  5921.         errno = ENOTSOCK;
  5922.  
  5923.     RETURN(result);
  5924.     return(result);
  5925. }
  5926.  
  5927. /******************************************************************************/
  5928.  
  5929. int
  5930. amiga_statfs(char *name,struct statfs *f)
  5931. {
  5932.     char localName[MAX_FILENAME_LEN];
  5933.     int result = ERROR;
  5934.  
  5935.     chkabort();
  5936.  
  5937.     ASSERT(name != NULL && f != NULL);
  5938.  
  5939.     ENTER();
  5940.  
  5941.     SHOWSTRING(name);
  5942.     SHOWVALUE(f);
  5943.  
  5944.     if(TranslateRelativePath(&name,localName,sizeof(localName)) == OK)
  5945.     {
  5946.         /* Make up something for the virtual root directory. */
  5947.         if(strcmp(name,"/") == SAME)
  5948.         {
  5949.             memset(f,0,sizeof(*f));
  5950.  
  5951.             f->f_fsize = 512;
  5952.  
  5953.             /* Try to reuse the data from our last scan. */
  5954.             if(RootBlocks > 0 && RootBlocksUsed > 0)
  5955.             {
  5956.                 f->f_blocks    = RootBlocks;
  5957.                 f->f_bfree    = RootBlocks - RootBlocksUsed;
  5958.             }
  5959.             else
  5960.             {
  5961.                 f->f_blocks    = 0x7FFFFFFF/f->f_fsize;
  5962.                 f->f_bfree    = f->f_blocks - 1;
  5963.             }
  5964.  
  5965.             f->f_bsize    = f->f_fsize;
  5966.             f->f_bavail    = f->f_bfree;
  5967.  
  5968.             SHOWVALUE(f->f_fsize);
  5969.             SHOWVALUE(f->f_bsize);
  5970.             SHOWVALUE(f->f_blocks);
  5971.             SHOWVALUE(f->f_bfree);
  5972.             SHOWVALUE(f->f_bavail);
  5973.  
  5974.             result = OK;
  5975.         }
  5976.         else
  5977.         {
  5978.             struct MangleInfo mi;
  5979.             BPTR fileLock;
  5980.  
  5981.             if(MangleName(&name,&mi) == OK)
  5982.             {
  5983.                 ForbidDOS();
  5984.  
  5985.                 fileLock = Lock(name,SHARED_LOCK);
  5986.                 if(fileLock != ZERO)
  5987.                 {
  5988.                     struct InfoData __aligned id;
  5989.  
  5990.                     if(Info(fileLock,&id))
  5991.                     {
  5992.                         memset(f,0,sizeof(*f));
  5993.  
  5994.                         /* Make sure that these never drop to zero. */
  5995.                         if(id.id_NumBlocks == 0)
  5996.                             id.id_NumBlocks = 1;
  5997.  
  5998.                         if(id.id_BytesPerBlock == 0)
  5999.                             id.id_BytesPerBlock = 512;
  6000.  
  6001.                         f->f_fsize    = id.id_BytesPerBlock;                        /* fundamental file system block size */
  6002.                         f->f_blocks    = id.id_NumBlocks;                            /* total data blocks in file system */
  6003.                         f->f_bfree    = id.id_NumBlocks - id.id_NumBlocksUsed;    /* free blocks in fs */
  6004.                         f->f_bsize    = f->f_fsize;                                /* optimal transfer block size */
  6005.                         f->f_bavail    = f->f_bfree;                                /* free blocks avail to non-superuser */
  6006.  
  6007.                         SHOWVALUE(f->f_fsize);
  6008.                         SHOWVALUE(f->f_bsize);
  6009.                         SHOWVALUE(f->f_blocks);
  6010.                         SHOWVALUE(f->f_bfree);
  6011.                         SHOWVALUE(f->f_bavail);
  6012.  
  6013.                         result = OK;
  6014.                     }
  6015.                     else
  6016.                     {
  6017.                         MapIoErrToErrno();
  6018.                     }
  6019.  
  6020.                     UnLock(fileLock);
  6021.                 }
  6022.                 else
  6023.                 {
  6024.                     MapIoErrToErrno();
  6025.                 }
  6026.  
  6027.                 PermitDOS();
  6028.  
  6029.                 UnmangleName(&name,&mi);
  6030.             }
  6031.         }
  6032.     }
  6033.  
  6034.     RETURN(result);
  6035.     return(result);
  6036. }
  6037.  
  6038. /******************************************************************************/
  6039.  
  6040. int
  6041. amiga_execl(char *path,char *arg,...)    /* dummy */
  6042. {
  6043.     int result;
  6044.  
  6045.     chkabort();
  6046.  
  6047.     ENTER();
  6048.  
  6049.     result = ERROR;
  6050.     errno = ENOSYS;
  6051.  
  6052.     RETURN(result);
  6053.     return(result);
  6054. }
  6055.  
  6056. /******************************************************************************/
  6057.  
  6058. char *
  6059. amiga_strerror(int error)
  6060. {
  6061.     struct TagItem tags[2];
  6062.     char *result;
  6063.  
  6064.     chkabort();
  6065.  
  6066.     ENTER();
  6067.  
  6068.     tags[0].ti_Tag    = SBTM_GETVAL(SBTC_ERRNOSTRPTR);
  6069.     tags[0].ti_Data    = error;
  6070.     tags[1].ti_Tag    = TAG_END;
  6071.  
  6072.     SocketBaseTagList(tags);
  6073.  
  6074.     result = (char *)tags[0].ti_Data;
  6075.  
  6076.     RETURN(result);
  6077.     return(result);
  6078. }
  6079.  
  6080. /******************************************************************************/
  6081.  
  6082. int
  6083. amiga_access(char *name,int modes)
  6084. {
  6085.     struct MangleInfo mi;
  6086.     int result = ERROR;
  6087.  
  6088.     chkabort();
  6089.  
  6090.     ASSERT(name != NULL);
  6091.  
  6092.     ENTER();
  6093.  
  6094.     if(MangleName(&name,&mi) == OK)
  6095.     {
  6096.         ForbidDOS();
  6097.         result = access(name,modes);
  6098.         PermitDOS();
  6099.  
  6100.         UnmangleName(&name,&mi);
  6101.     }
  6102.  
  6103.     RETURN(result);
  6104.     return(result);
  6105. }
  6106.  
  6107. /******************************************************************************/
  6108.  
  6109. STATIC VOID
  6110. MapIoErrToErrno(VOID)
  6111. {
  6112.     /* This routine maps AmigaDOS error codes to
  6113.      * Unix error codes, as far as this is possible.
  6114.      * This table contains AmigaDOS error codes
  6115.      * the emulated routines won't generate. I have
  6116.      * included them for the sake of completeness.
  6117.      */
  6118.     struct { LONG IoErr; LONG errno; } MapTable[] =
  6119.     {
  6120.         ERROR_NO_FREE_STORE,            ENOMEM,
  6121.         ERROR_TASK_TABLE_FULL,            ENOMEM,
  6122.         ERROR_BAD_TEMPLATE,                EINVAL,
  6123.         ERROR_BAD_NUMBER,                EINVAL,
  6124.         ERROR_REQUIRED_ARG_MISSING,        EINVAL,
  6125.         ERROR_KEY_NEEDS_ARG,            EINVAL,
  6126.         ERROR_TOO_MANY_ARGS,            EINVAL,
  6127.         ERROR_UNMATCHED_QUOTES,            EINVAL,
  6128.         ERROR_LINE_TOO_LONG,            ENAMETOOLONG,
  6129.         ERROR_FILE_NOT_OBJECT,            ENOEXEC,
  6130.         ERROR_INVALID_RESIDENT_LIBRARY,    EIO,
  6131.         ERROR_NO_DEFAULT_DIR,            EIO,
  6132.         ERROR_OBJECT_IN_USE,            EBUSY,
  6133.         ERROR_OBJECT_EXISTS,            EBUSY,
  6134.         ERROR_DIR_NOT_FOUND,            ENOENT,
  6135.         ERROR_OBJECT_NOT_FOUND,            ENOENT,
  6136.         ERROR_BAD_STREAM_NAME,            EINVAL,
  6137.         ERROR_OBJECT_TOO_LARGE,            EFBIG,
  6138.         ERROR_ACTION_NOT_KNOWN,            ENOSYS,
  6139.         ERROR_INVALID_COMPONENT_NAME,    EINVAL,
  6140.         ERROR_INVALID_LOCK,                EBADF,
  6141.         ERROR_OBJECT_WRONG_TYPE,        EFTYPE,
  6142.         ERROR_DISK_NOT_VALIDATED,        EROFS,
  6143.         ERROR_DISK_WRITE_PROTECTED,        EROFS,
  6144.         ERROR_RENAME_ACROSS_DEVICES,    EXDEV,
  6145.         ERROR_DIRECTORY_NOT_EMPTY,        ENOTEMPTY,
  6146.         ERROR_TOO_MANY_LEVELS,            ENAMETOOLONG,
  6147.         ERROR_DEVICE_NOT_MOUNTED,        ENXIO,
  6148.         ERROR_SEEK_ERROR,                EIO,
  6149.         ERROR_COMMENT_TOO_BIG,            ENAMETOOLONG,
  6150.         ERROR_DISK_FULL,                ENOSPC,
  6151.         ERROR_DELETE_PROTECTED,            EACCES,
  6152.         ERROR_WRITE_PROTECTED,            EACCES,
  6153.         ERROR_READ_PROTECTED,            EACCES,
  6154.         ERROR_NOT_A_DOS_DISK,            EFTYPE,
  6155.         ERROR_NO_DISK,                    EACCES,
  6156.         ERROR_NO_MORE_ENTRIES,            EIO,
  6157.         ERROR_IS_SOFT_LINK,                EFTYPE,
  6158.         ERROR_OBJECT_LINKED,            EIO,
  6159.         ERROR_BAD_HUNK,                    ENOEXEC,
  6160.         ERROR_NOT_IMPLEMENTED,            ENOSYS,
  6161.         ERROR_RECORD_NOT_LOCKED,        EIO,
  6162.         ERROR_LOCK_COLLISION,            EACCES,
  6163.         ERROR_LOCK_TIMEOUT,                EIO,
  6164.         ERROR_UNLOCK_ERROR,                EIO,
  6165.         ERROR_BUFFER_OVERFLOW,            EIO,
  6166.         ERROR_BREAK,                    EINTR,
  6167.         ERROR_NOT_EXECUTABLE,            ENOEXEC
  6168.     };
  6169.  
  6170.     LONG ioErr = IoErr();
  6171.     int i;
  6172.  
  6173.     /* If nothing else matches, we can always
  6174.      * flag it as an I/O error.
  6175.      */
  6176.     errno = EIO;
  6177.  
  6178.     for(i = 0 ; i < NUM_ENTRIES(MapTable) ; i++)
  6179.     {
  6180.         if(MapTable[i].IoErr == ioErr)
  6181.         {
  6182.             errno = MapTable[i].errno;
  6183.             break;
  6184.         }
  6185.     }
  6186. }
  6187.  
  6188. /******************************************************************************/
  6189.  
  6190. off_t
  6191. amiga_lseek(int fd,off_t offset,int mode)
  6192. {
  6193.     struct UFB * ufb;
  6194.     off_t result = ERROR;
  6195.  
  6196.     ENTER();
  6197.     SHOWVALUE(fd);
  6198.     SHOWVALUE(offset);
  6199.     SHOWVALUE(mode);
  6200.  
  6201.     ForbidDOS();
  6202.  
  6203.     /* Make sure that we operate on a file. */
  6204.     ufb = chkufb(fd);
  6205.     if(ufb != NULL && FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_SOCKET))
  6206.         result = lseek(fd,offset,mode);
  6207.     else
  6208.         errno = EBADF;
  6209.  
  6210.     PermitDOS();
  6211.  
  6212.     RETURN(result);
  6213.     return(result);
  6214. }
  6215.  
  6216. /******************************************************************************/
  6217.  
  6218. int
  6219. amiga_chroot(char *name)    /* dummy */
  6220. {
  6221.     int result = OK;
  6222.  
  6223.     ENTER();
  6224.  
  6225.     SHOWSTRING(name);
  6226.  
  6227.     RETURN(result);
  6228.     return(result);
  6229. }
  6230.  
  6231. /******************************************************************************/
  6232.  
  6233. STATIC int
  6234. MapFileNameAmigaToUnix(
  6235.     const char *    amiga,
  6236.     char *            unix,
  6237.     int                maxUnixLen)
  6238. {
  6239.     int len,destLen;
  6240.     int result = ERROR;
  6241.  
  6242.     /* This routine makes a Unix file
  6243.      * name generated from an AmigaDOS
  6244.      * file name. This involves a slight
  6245.      * change of syntax...
  6246.      */
  6247.     D(("amiga name |%s|",amiga));
  6248.  
  6249.     len = destLen = strlen(amiga);
  6250.     if(amiga[0] == '/')
  6251.     {
  6252.         destLen = 2 + len;
  6253.     }
  6254.     else
  6255.     {
  6256.         int i;
  6257.  
  6258.         for(i = 0 ; i < len ; i++)
  6259.         {
  6260.             if(amiga[i] == ':')
  6261.             {
  6262.                 if(amiga[i+1] != '\0')
  6263.                     destLen = 1 + len;
  6264.  
  6265.                 break;
  6266.             }
  6267.         }
  6268.     }
  6269.  
  6270.     if(destLen < maxUnixLen)
  6271.     {
  6272.         if(amiga[0] == '/')
  6273.         {
  6274.             /* `/foo\0' -> `../foo\0' */
  6275.             memmove(&unix[2],amiga,len+1);
  6276.             strncpy(unix,"..",2);
  6277.         }
  6278.         else
  6279.         {
  6280.             BOOL done = FALSE;
  6281.             int i;
  6282.  
  6283.             for(i = 0 ; i < len ; i++)
  6284.             {
  6285.                 if(amiga[i] == ':')
  6286.                 {
  6287.                     if(amiga[i+1] == '\0')
  6288.                     {
  6289.                         /* `foo:\0' -> `/foo\0' */
  6290.                         memmove(&unix[1],amiga,i);
  6291.                         unix[0] = '/';
  6292.                         unix[i+1] = '\0';
  6293.                     }
  6294.                     else
  6295.                     {
  6296.                         /* `foo:bar\0' -> `/foo/bar\0' */
  6297.                         memmove(&unix[1],amiga,len+1);
  6298.                         unix[0] = '/';
  6299.                         unix[i+1] = '/';
  6300.                     }
  6301.  
  6302.                     done = TRUE;
  6303.                     break;
  6304.                 }
  6305.             }
  6306.  
  6307.             if(NOT done && unix != amiga)
  6308.                 strcpy(unix,amiga);
  6309.         }
  6310.  
  6311.         D(("unix name |%s|",unix));
  6312.  
  6313.         result = OK;
  6314.     }
  6315.     else
  6316.     {
  6317.         SHOWMSG("unix name is too long to fit");
  6318.  
  6319.         errno = ENAMETOOLONG;
  6320.     }
  6321.  
  6322.     return(result);
  6323. }
  6324.  
  6325. /******************************************************************************/
  6326.  
  6327. STATIC VOID
  6328. FlushSTDOUT(VOID)
  6329. {
  6330.     /* Flush the standard output streams so that
  6331.      * any following output will be printed after
  6332.      * any buffered stdio output.
  6333.      */
  6334.     if(WBenchMsg == NULL)
  6335.     {
  6336.         struct UFB * ufb;
  6337.  
  6338.         /* Don't let anybody stop us. */
  6339.         signal(SIGINT,SIG_IGN);
  6340.         signal(SIGTERM,SIG_IGN);
  6341.  
  6342.         ufb = chkufb(fileno(stdout));
  6343.         if(ufb != NULL && FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_SOCKET))
  6344.             fflush(stdout);
  6345.  
  6346.         ufb = chkufb(fileno(stderr));
  6347.         if(ufb != NULL && FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_SOCKET))
  6348.             fflush(stderr);
  6349.     }
  6350. }
  6351.  
  6352. VOID
  6353. _CXOVF(VOID)
  6354. {
  6355.     /* This routine is called when a stack overflow occurs. */
  6356.     FlushSTDOUT();
  6357.     ReportProblem("Stack overflow");
  6358.  
  6359.     exit(RETURN_ERROR);
  6360. }
  6361.  
  6362. VOID __regargs
  6363. _CXBRK(VOID)
  6364. {
  6365.     extern STRPTR _ProgramName;
  6366.  
  6367.     FlushSTDOUT();
  6368.  
  6369.     /* This routine is called when the program is interrupted. */
  6370.     if(DOSBase->lib_Version >= 37)
  6371.     {
  6372.         PrintFault(ERROR_BREAK,_ProgramName);
  6373.     }
  6374.     else
  6375.     {
  6376.         const char *famousLastWords = ": *** Break";
  6377.         BPTR output = Output();
  6378.  
  6379.         Write(output,(APTR)famousLastWords,strlen(famousLastWords));
  6380.         Write(output,_ProgramName,strlen(_ProgramName));
  6381.         Write(output,"\n",1);
  6382.     }
  6383.  
  6384.     exit(RETURN_WARN);
  6385. }
  6386.  
  6387. /******************************************************************************/
  6388.  
  6389. STATIC STRPTR SambaSemaphoreName = "Amiga Samba";
  6390.  
  6391. struct SambaClientNode
  6392. {
  6393.     struct MinNode    scn_MinNode;
  6394.     struct Task *    scn_Task;
  6395.     pid_t            scn_PID;
  6396. };
  6397.  
  6398. struct SambaSemaphore
  6399. {
  6400.     struct SignalSemaphore    ss_Semaphore;
  6401.     struct List                ss_ClientList;
  6402.     pid_t                    ss_PID;
  6403.     struct List                ss_FileLockList;
  6404. };
  6405.  
  6406. STATIC struct SambaSemaphore *    SambaSemaphore;
  6407. STATIC struct SambaClientNode *    ThisClient;
  6408.  
  6409. STATIC VOID
  6410. CleanupSambaSemaphore(VOID)
  6411. {
  6412.     if(ThisClient != NULL)
  6413.     {
  6414.         /* Unregister the program. */
  6415.         ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6416.         Remove((struct Node *)ThisClient);
  6417.         ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6418.  
  6419.         FreeVec(ThisClient);
  6420.         ThisClient = NULL;
  6421.     }
  6422. }
  6423.  
  6424. STATIC BOOL
  6425. SetupSambaSemaphore(VOID)
  6426. {
  6427.     BOOL success = FALSE;
  6428.  
  6429.     /* We have to have the timer open to serialize the process IDs properly. */
  6430.     if(TimerBase != NULL)
  6431.     {
  6432.         Forbid();
  6433.  
  6434.         /* Try to find the global rendezvous semaphore. */
  6435.         SambaSemaphore = (struct SambaSemaphore *)FindSemaphore(SambaSemaphoreName);
  6436.         if(SambaSemaphore == NULL)
  6437.         {
  6438.             /* Couldn't find it. So, we create it... */
  6439.             SambaSemaphore = AllocMem(sizeof(*SambaSemaphore) + strlen(SambaSemaphoreName)+1,MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
  6440.             if(SambaSemaphore != NULL)
  6441.             {
  6442.                 /* Set up the name. */
  6443.                 SambaSemaphore->ss_Semaphore.ss_Link.ln_Name = (char *)(SambaSemaphore+1);
  6444.                 strcpy(SambaSemaphore->ss_Semaphore.ss_Link.ln_Name,SambaSemaphoreName);
  6445.  
  6446.                 /* Set the base value for all process IDs. */
  6447.                 SambaSemaphore->ss_PID = 936;
  6448.  
  6449.                 /* Clear the client list tasks are going to be registered with. */
  6450.                 NewList(&SambaSemaphore->ss_ClientList);
  6451.  
  6452.                 /* Clear the list we will use for keeping
  6453.                  * track of file segment locks.
  6454.                  */
  6455.                 NewList(&SambaSemaphore->ss_FileLockList);
  6456.  
  6457.                 AddSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6458.             }
  6459.         }
  6460.  
  6461.         Permit();
  6462.     }
  6463.  
  6464.     /* If possible, register this task. */
  6465.     if(SambaSemaphore != NULL)
  6466.     {
  6467.         struct SambaClientNode * scn;
  6468.  
  6469.         scn = AllocVec(sizeof(*scn),MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
  6470.         if(scn != NULL)
  6471.         {
  6472.             /* That's me. */
  6473.             scn->scn_Task = FindTask(NULL);
  6474.  
  6475.             ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6476.  
  6477.             /* Register this program with a new process ID. */
  6478.             scn->scn_PID = SambaSemaphore->ss_PID++;
  6479.             AddTail(&SambaSemaphore->ss_ClientList,(struct Node *)scn);
  6480.  
  6481.             ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6482.  
  6483.             ThisClient = scn;
  6484.  
  6485.             success = TRUE;
  6486.         }
  6487.     }
  6488.  
  6489.     return(success);
  6490. }
  6491.  
  6492. int
  6493. amiga_kill(pid_t pid,int sig)
  6494. {
  6495.     struct SambaClientNode * scn;
  6496.     struct Task * found = NULL;
  6497.     int result = ERROR;
  6498.  
  6499.     chkabort();
  6500.  
  6501.     ENTER();
  6502.  
  6503.     ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6504.  
  6505.     /* Try to find the Samba program that responds
  6506.      * to the given process ID.
  6507.      */
  6508.     for(scn = (struct SambaClientNode *)SambaSemaphore->ss_ClientList.lh_Head ;
  6509.         scn->scn_MinNode.mln_Succ != NULL ;
  6510.         scn = (struct SambaClientNode *)scn->scn_MinNode.mln_Succ)
  6511.     {
  6512.         if(scn->scn_PID == pid)
  6513.         {
  6514.             found = scn->scn_Task;
  6515.             break;
  6516.         }
  6517.     }
  6518.  
  6519.     /* Did we find one? */
  6520.     if(found != NULL)
  6521.     {
  6522.         /* Kill the task or just do nothing? */
  6523.         if(sig == SIGTERM)
  6524.             Signal(found,SIGBREAKF_CTRL_C);
  6525.  
  6526.         result = OK;
  6527.     }
  6528.     else
  6529.     {
  6530.         errno = ESRCH;
  6531.     }
  6532.  
  6533.     ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6534.  
  6535.     RETURN(result);
  6536.     return(result);
  6537. }
  6538.  
  6539. pid_t
  6540. amiga_getpid(VOID)
  6541. {
  6542.     pid_t result;
  6543.  
  6544.     chkabort();
  6545.  
  6546.     ENTER();
  6547.  
  6548.     /* Return this program's process ID. */
  6549.     result = ThisClient->scn_PID;
  6550.  
  6551.     RETURN(result);
  6552.     return(result);
  6553. }
  6554.  
  6555. /******************************************************************************/
  6556.  
  6557. struct LockedRegionNode
  6558. {
  6559.     struct MinNode    lrn_MinNode;
  6560.     LONG            lrn_Start;
  6561.     LONG            lrn_Stop;
  6562.     pid_t            lrn_Owner;
  6563.     BOOL            lrn_Shared;
  6564. };
  6565.  
  6566. struct FileLockNode
  6567. {
  6568.     struct MinNode    fln_MinNode;
  6569.     struct List        fln_LockedRegionList;
  6570.     BPTR            fln_FileParentDir;
  6571.     UBYTE            fln_FileName[1];
  6572. };
  6573.  
  6574. STATIC VOID
  6575. RemoveLockedRegionNode(struct UFB * ufb,LONG start,LONG stop)
  6576. {
  6577.     if(FLAG_IS_SET(ufb->ufbflg,UFB_LOCKED))
  6578.     {
  6579.         BPTR fileHandle = (BPTR)ufb->ufbfh;
  6580.         struct FileLockNode * whichLock;
  6581.  
  6582.         /* Find the locked file this descriptor
  6583.          * buffer belongs to.
  6584.          */
  6585.         if(FindFileLockNodeByFileHandle(fileHandle,&whichLock) == OK && whichLock != NULL)
  6586.         {
  6587.             struct LockedRegionNode * lrn;
  6588.  
  6589.             /* Find the region to unlock and remove it. */
  6590.             for(lrn = (struct LockedRegionNode *)whichLock->fln_LockedRegionList.lh_Head ;
  6591.                 lrn->lrn_MinNode.mln_Succ != NULL ;
  6592.                 lrn = (struct LockedRegionNode *)lrn->lrn_MinNode.mln_Succ)
  6593.             {
  6594.                 if(lrn->lrn_Owner == ThisClient->scn_PID &&
  6595.                    lrn->lrn_Start == start &&
  6596.                    lrn->lrn_Stop  == stop)
  6597.                 {
  6598.                     SHOWMSG("unlocking all regions on this file");
  6599.  
  6600.                     Remove((struct Node *)lrn);
  6601.                     DeleteLockedRegionNode(lrn);
  6602.                     break;
  6603.                 }
  6604.             }
  6605.  
  6606.             /* Check if there are any locked regions left.
  6607.              * If not, mark the entire file as unlocked.
  6608.              */
  6609.             if(IsListEmpty(&whichLock->fln_LockedRegionList))
  6610.             {
  6611.                 SHOWMSG("no more regions are locked; removing the file lock node");
  6612.  
  6613.                 Remove((struct Node *)whichLock);
  6614.  
  6615.                 DeleteFileLockNode(whichLock);
  6616.  
  6617.                 CLEAR_FLAG(ufb->ufbflg,UFB_LOCKED);
  6618.             }
  6619.         }
  6620.     }
  6621. }
  6622.  
  6623. STATIC VOID
  6624. DeleteLockedRegionNode(struct LockedRegionNode * lrn)
  6625. {
  6626.     if(lrn != NULL)
  6627.         FreeMem(lrn,sizeof(*lrn));
  6628. }
  6629.  
  6630. STATIC LONG
  6631. CreateLockedRegionNode(struct LockedRegionNode ** resultPtr)
  6632. {
  6633.     struct LockedRegionNode * lrn;
  6634.     LONG error;
  6635.  
  6636.     lrn = AllocMem(sizeof(*lrn),MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
  6637.     if(lrn != NULL)
  6638.     {
  6639.         lrn->lrn_Owner = ThisClient->scn_PID;
  6640.  
  6641.         error = OK;
  6642.     }
  6643.     else
  6644.     {
  6645.         error = ERROR_NO_FREE_STORE;
  6646.     }
  6647.  
  6648.     (*resultPtr) = lrn;
  6649.  
  6650.     return(error);
  6651. }
  6652.  
  6653. STATIC VOID
  6654. DeleteFileLockNode(struct FileLockNode * fln)
  6655. {
  6656.     if(fln != NULL)
  6657.     {
  6658.         UnLock(fln->fln_FileParentDir);
  6659.         FreeVec(fln);
  6660.     }
  6661. }
  6662.  
  6663. STATIC LONG
  6664. CreateFileLockNode(struct UFB * ufb,struct FileLockNode ** resultPtr)
  6665. {
  6666.     struct FileLockNode * result = NULL;
  6667.     BPTR fileHandle = (BPTR)ufb->ufbfh;
  6668.     struct FileInfoBlock __aligned fib;
  6669.     LONG error = OK;
  6670.  
  6671.     /* We store a lock on the file's parent directory
  6672.      * and the name of the file for later use in
  6673.      * comparisons.
  6674.      */
  6675.     if(ExamineFH(fileHandle,&fib))
  6676.     {
  6677.         struct FileLockNode * fln;
  6678.  
  6679.         fln = AllocVec(sizeof(*fln) + strlen(fib.fib_FileName),MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
  6680.         if(fln != NULL)
  6681.         {
  6682.             fln->fln_FileParentDir = ParentOfFH(fileHandle);
  6683.             if(fln->fln_FileParentDir != ZERO)
  6684.             {
  6685.                 strcpy(fln->fln_FileName,fib.fib_FileName);
  6686.  
  6687.                 NewList(&fln->fln_LockedRegionList);
  6688.  
  6689.                 result = fln;
  6690.                 fln = NULL;
  6691.             }
  6692.             else
  6693.             {
  6694.                 error = IoErr();
  6695.             }
  6696.  
  6697.             DeleteFileLockNode(fln);
  6698.         }
  6699.         else
  6700.         {
  6701.             error = ERROR_NO_FREE_STORE;
  6702.         }
  6703.     }
  6704.     else
  6705.     {
  6706.         error = IoErr();
  6707.     }
  6708.  
  6709.     (*resultPtr) = result;
  6710.  
  6711.     return(error);
  6712. }
  6713.  
  6714. STATIC LONG
  6715. FindFileLockNodeByFileHandle(BPTR fileHandle,struct FileLockNode ** resultPtr)
  6716. {
  6717.     struct FileLockNode * result = NULL;
  6718.     BPTR parentDir;
  6719.     LONG error;
  6720.  
  6721.     /* Determine the file's parent directory and
  6722.      * name. These will be compared against the
  6723.      * global file lock data.
  6724.      */
  6725.     parentDir = ParentOfFH(fileHandle);
  6726.     if(parentDir != ZERO)
  6727.     {
  6728.         struct FileInfoBlock __aligned this_fib;
  6729.  
  6730.         if(ExamineFH(fileHandle,&this_fib))
  6731.         {
  6732.             struct FileLockNode * fln;
  6733.  
  6734.             #if DEBUG
  6735.             {
  6736.                 char name[MAX_FILENAME_LEN];
  6737.  
  6738.                 if(NameFromFH(fileHandle,name,sizeof(name)))
  6739.                     D(("Looking for a lock on file |%s|",name));
  6740.             }
  6741.             #endif /* DEBUG */
  6742.  
  6743.             error = OK;
  6744.  
  6745.             for(fln = (struct FileLockNode *)SambaSemaphore->ss_FileLockList.lh_Head ;
  6746.                 fln->fln_MinNode.mln_Succ != NULL ;
  6747.                 fln = (struct FileLockNode *)fln->fln_MinNode.mln_Succ)
  6748.             {
  6749.                 /* To be identical, the files must reside in the
  6750.                  * same directories and bear the same names.
  6751.                  */
  6752.                 if(SameLock(fln->fln_FileParentDir,parentDir) == LOCK_SAME)
  6753.                 {
  6754.                     if(Stricmp(fln->fln_FileName,this_fib.fib_FileName) == SAME)
  6755.                     {
  6756.                         result = fln;
  6757.                         error = OK;
  6758.  
  6759.                         break;
  6760.                     }
  6761.                 }
  6762.             }
  6763.         }
  6764.         else
  6765.         {
  6766.             error = IoErr();
  6767.         }
  6768.  
  6769.         if(result != NULL)
  6770.             SHOWMSG("found one");
  6771.         else
  6772.             SHOWMSG("didn't find one");
  6773.  
  6774.         UnLock(parentDir);
  6775.     }
  6776.     else
  6777.     {
  6778.         error = IoErr();
  6779.     }
  6780.  
  6781.     (*resultPtr) = result;
  6782.  
  6783.     return(error);
  6784. }
  6785.  
  6786. STATIC VOID
  6787. FindFileLockNodeByDrawerAndName(BPTR dirLock,STRPTR fileName,struct FileLockNode ** resultPtr)
  6788. {
  6789.     struct FileLockNode * result = NULL;
  6790.     struct FileLockNode * fln;
  6791.  
  6792.     /* This is a somewhat simplied version of FindFileLockNodeByFileHandle()
  6793.      * which works with preset drawer and name data.
  6794.      */
  6795.  
  6796.     #if DEBUG
  6797.     {
  6798.         char name[MAX_FILENAME_LEN];
  6799.  
  6800.         if(NameFromLock(dirLock,name,sizeof(name)))
  6801.         {
  6802.             if(AddPart(name,fileName,sizeof(name)))
  6803.                 D(("Looking for a lock on file |%s|",name));
  6804.         }
  6805.     }
  6806.     #endif /* DEBUG */
  6807.  
  6808.     for(fln = (struct FileLockNode *)SambaSemaphore->ss_FileLockList.lh_Head ;
  6809.         fln->fln_MinNode.mln_Succ != NULL ;
  6810.         fln = (struct FileLockNode *)fln->fln_MinNode.mln_Succ)
  6811.     {
  6812.         if(SameLock(fln->fln_FileParentDir,dirLock) == LOCK_SAME)
  6813.         {
  6814.             if(Stricmp(fln->fln_FileName,fileName) == SAME)
  6815.             {
  6816.                 result = fln;
  6817.  
  6818.                 break;
  6819.             }
  6820.         }
  6821.     }
  6822.  
  6823.     if(result != NULL)
  6824.         SHOWMSG("found one");
  6825.     else
  6826.         SHOWMSG("didn't find one");
  6827.  
  6828.     (*resultPtr) = result;
  6829. }
  6830.  
  6831. STATIC struct LockedRegionNode *
  6832. FindCollidingRegion(struct FileLockNode * fln,LONG start,LONG stop,BOOL shared)
  6833. {
  6834.     struct LockedRegionNode * result = NULL;
  6835.     struct LockedRegionNode * lrn;
  6836.  
  6837.     /* This routine looks for a locked region that overlaps
  6838.      * with the specified region. It returns a pointer to the
  6839.      * region that would collide with the specified region if
  6840.      * a new lock were to be added.
  6841.      */
  6842.     for(lrn = (struct LockedRegionNode *)fln->fln_LockedRegionList.lh_Head ;
  6843.         lrn->lrn_MinNode.mln_Succ != NULL ;
  6844.         lrn = (struct LockedRegionNode *)lrn->lrn_MinNode.mln_Succ)
  6845.     {
  6846.         /* Do the regions overlap? */
  6847.         if(lrn->lrn_Start <= stop && start <= lrn->lrn_Stop)
  6848.         {
  6849.             /* Two shared regions may always overlap.
  6850.              * How about the rest?
  6851.              */
  6852.             if(NOT shared || NOT lrn->lrn_Shared)
  6853.             {
  6854.                 /* The lock owner may add as many exclusive
  6855.                  * or shared locks to the same region as
  6856.                  * necessary.
  6857.                  */
  6858.                 if(lrn->lrn_Owner == ThisClient->scn_PID)
  6859.                     continue;
  6860.  
  6861.                 /* So we found a region that would
  6862.                  * cause a collision.
  6863.                  */
  6864.                 result = lrn;
  6865.                 break;
  6866.             }
  6867.         }
  6868.     }
  6869.  
  6870.     return(result);
  6871. }
  6872.  
  6873. STATIC VOID
  6874. CleanupFileLocks(int fd)
  6875. {
  6876.     struct UFB * ufb;
  6877.  
  6878.     /* This routine removes all locked regions from a file
  6879.      * before it is eventually closed.
  6880.      */
  6881.  
  6882.     ufb = chkufb(fd);
  6883.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_LOCKED))
  6884.     {
  6885.         BPTR fileHandle = (BPTR)ufb->ufbfh;
  6886.         struct FileLockNode * whichLock;
  6887.  
  6888.         ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6889.  
  6890.         if(FindFileLockNodeByFileHandle(fileHandle,&whichLock) == OK && whichLock != NULL)
  6891.         {
  6892.             struct LockedRegionNode * lrn_this;
  6893.             struct LockedRegionNode * lrn_next;
  6894.  
  6895.             SHOWMSG("unlocking all regions on this file");
  6896.  
  6897.             for(lrn_this = (struct LockedRegionNode *)whichLock->fln_LockedRegionList.lh_Head ;
  6898.                (lrn_next = (struct LockedRegionNode *)lrn_this->lrn_MinNode.mln_Succ) != NULL ;
  6899.                 lrn_this = lrn_next)
  6900.             {
  6901.                 if(lrn_this->lrn_Owner == ThisClient->scn_PID)
  6902.                 {
  6903.                     Remove((struct Node *)lrn_this);
  6904.                     DeleteLockedRegionNode(lrn_this);
  6905.                 }
  6906.             }
  6907.  
  6908.             if(IsListEmpty(&whichLock->fln_LockedRegionList))
  6909.             {
  6910.                 SHOWMSG("no more regions are locked; removing the file lock node");
  6911.  
  6912.                 Remove((struct Node *)whichLock);
  6913.  
  6914.                 DeleteFileLockNode(whichLock);
  6915.             }
  6916.         }
  6917.  
  6918.         CLEAR_FLAG(ufb->ufbflg,UFB_LOCKED);
  6919.  
  6920.         ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6921.     }
  6922. }
  6923.  
  6924. #define SEEK_ERROR (-1)
  6925.  
  6926. STATIC int
  6927. HandleFileLocking(int cmd,struct flock * l,struct UFB * ufb)
  6928. {
  6929.     int result = ERROR;
  6930.  
  6931.     /* This routine implements advisory file segment locking
  6932.      * similar to 4.4BSD, but not quite the same. The functionality
  6933.      * is a subset, somewhat similar to the functionality offered
  6934.      * by the AmigaDOS LockRecord() and UnlockRecord() functions.
  6935.      * This means for example that every unlock request must
  6936.      * match the size and position of the corresponding locking
  6937.      * request.
  6938.      *
  6939.      * This implementation was chosen because not every Amiga
  6940.      * filing system implements record locking and Samba
  6941.      * absolutely requires this functionality to work.
  6942.      */
  6943.     if(l != NULL && ufb != NULL)
  6944.     {
  6945.         /* Can we make sense of the input parameters? */
  6946.         if(F_RDLCK <= l->l_type && l->l_type <= F_WRLCK &&
  6947.           (l->l_whence == SEEK_SET || l->l_whence == SEEK_CUR || l->l_whence == SEEK_END))
  6948.         {
  6949.             struct LockedRegionNode * lrn = NULL;
  6950.             struct FileLockNode * fln = NULL;
  6951.             LONG error;
  6952.  
  6953.             if((cmd == F_SETLK || cmd == F_SETLKW) && (l->l_type != F_UNLCK))
  6954.             {
  6955.                 SHOWMSG("this is a lock request");
  6956.                 error = CreateFileLockNode(ufb,&fln);
  6957.                 if(error == OK)
  6958.                     error = CreateLockedRegionNode(&lrn);
  6959.             }
  6960.             else
  6961.             {
  6962.                 SHOWMSG("this is not a lock request");
  6963.                 error = OK;
  6964.             }
  6965.  
  6966.             if(error == OK)
  6967.             {
  6968.                 struct FileInfoBlock __aligned fib;
  6969.                 BPTR fileHandle = (BPTR)ufb->ufbfh;
  6970.                 BOOL dataIsValid = TRUE;
  6971.                 LONG currentPosition;
  6972.                 LONG start = 0;
  6973.                 LONG len = 0;
  6974.  
  6975.                 /* Now calculate the position of the
  6976.                  * first byte to lock and the number
  6977.                  * of bytes to lock.
  6978.                  */
  6979.                 switch(l->l_whence)
  6980.                 {
  6981.                     case SEEK_SET:
  6982.  
  6983.                         start = l->l_start;
  6984.  
  6985.                         if(l->l_len == 0)
  6986.                         {
  6987.                             if(ExamineFH(fileHandle,&fib))
  6988.                                 len = fib.fib_Size - start;
  6989.                             else
  6990.                                 dataIsValid = FALSE;
  6991.                         }
  6992.                         else
  6993.                         {
  6994.                             len = l->l_len;
  6995.                         }
  6996.  
  6997.                         break;
  6998.  
  6999.                     case SEEK_CUR:
  7000.  
  7001.                         currentPosition = Seek(fileHandle,0,OFFSET_CURRENT);
  7002.                         if(currentPosition != SEEK_ERROR)
  7003.                         {
  7004.                             start = currentPosition + l->l_start;
  7005.  
  7006.                             if(l->l_len == 0)
  7007.                             {
  7008.                                 if(ExamineFH(fileHandle,&fib))
  7009.                                     len = fib.fib_Size - start;
  7010.                                 else
  7011.                                     dataIsValid = FALSE;
  7012.                             }
  7013.                             else
  7014.                             {
  7015.                                 len = l->l_len;
  7016.                             }
  7017.                         }
  7018.                         else
  7019.                         {
  7020.                             dataIsValid = FALSE;
  7021.                         }
  7022.  
  7023.                         break;
  7024.  
  7025.                     case SEEK_END:
  7026.                     default:
  7027.  
  7028.                         if(ExamineFH(fileHandle,&fib))
  7029.                         {
  7030.                             start = fib.fib_Size + l->l_start;
  7031.  
  7032.                             if(l->l_len == 0)
  7033.                                 len = fib.fib_Size - start;
  7034.                             else
  7035.                                 len = l->l_len;
  7036.                         }
  7037.                         else
  7038.                         {
  7039.                             dataIsValid = FALSE;
  7040.                         }
  7041.  
  7042.                         break;
  7043.                 }
  7044.  
  7045.                 SHOWVALUE(start);
  7046.                 SHOWVALUE(len);
  7047.  
  7048.                 /* Did we get everything we needed? */
  7049.                 if(dataIsValid)
  7050.                 {
  7051.                     if(start >= 0 && len >= 0)
  7052.                     {
  7053.                         if(len > 0)
  7054.                         {
  7055.                             if(l->l_type == F_UNLCK)
  7056.                             {
  7057.                                 D(("unlocking %ld..%ld",start,start+len-1));
  7058.  
  7059.                                 ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7060.  
  7061.                                 RemoveLockedRegionNode(ufb,start,start+len-1);
  7062.  
  7063.                                 ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7064.  
  7065.                                 result = OK;
  7066.                             }
  7067.                             else if(cmd == F_SETLKW)
  7068.                             {
  7069.                                 BPTR parentDir;
  7070.  
  7071.                                 D(("  locking %ld..%ld",start,start+len-1));
  7072.  
  7073.                                 parentDir = ParentOfFH(fileHandle);
  7074.                                 if(parentDir != ZERO)
  7075.                                 {
  7076.                                     struct FileInfoBlock __aligned fib;
  7077.  
  7078.                                     if(ExamineFH(fileHandle,&fib))
  7079.                                     {
  7080.                                         BOOL shared = (BOOL)(l->l_type == F_RDLCK);
  7081.                                         struct FileLockNode * existing_fln;
  7082.                                         BOOL stopped = FALSE;
  7083.                                         BOOL locked;
  7084.  
  7085.                                         if(shared)
  7086.                                             D(("this is a shared lock; waiting for completion"));
  7087.                                         else
  7088.                                             D(("this is an exclusive lock; waiting for completion"));
  7089.  
  7090.                                         lrn->lrn_Start    = start;
  7091.                                         lrn->lrn_Stop    = start+len-1;
  7092.                                         lrn->lrn_Shared    = shared;
  7093.  
  7094.                                         /* Retry until we manage to lock the record. */
  7095.                                         locked = FALSE;
  7096.                                         do
  7097.                                         {
  7098.                                             ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7099.  
  7100.                                             FindFileLockNodeByDrawerAndName(parentDir,fib.fib_FileName,&existing_fln);
  7101.                                             if(existing_fln != NULL)
  7102.                                             {
  7103.                                                 SHOWMSG("that file is already locked by someone");
  7104.  
  7105.                                                 if(FindCollidingRegion(existing_fln,start,start+len-1,shared) == NULL)
  7106.                                                 {
  7107.                                                     SHOWMSG("but the locks don't collide");
  7108.  
  7109.                                                     AddTail(&existing_fln->fln_LockedRegionList,(struct Node *)lrn);
  7110.                                                     lrn = NULL;
  7111.  
  7112.                                                     locked = TRUE;
  7113.                                                 }
  7114.                                                 else
  7115.                                                 {
  7116.                                                     SHOWMSG("and the locks collide");
  7117.                                                 }
  7118.                                             }
  7119.                                             else
  7120.                                             {
  7121.                                                 SHOWMSG("nobody has any locks on this file");
  7122.  
  7123.                                                 AddTail(&SambaSemaphore->ss_FileLockList,(struct Node *)fln);
  7124.                                                 AddTail(&fln->fln_LockedRegionList,(struct Node *)lrn);
  7125.  
  7126.                                                 fln = NULL;
  7127.                                                 lrn = NULL;
  7128.  
  7129.                                                 locked = TRUE;
  7130.                                             }
  7131.  
  7132.                                             ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7133.  
  7134.                                             if(NOT locked)
  7135.                                             {
  7136.                                                 const int randMax = RAND_MAX / 65536;
  7137.                                                 LONG numRandomTicks;
  7138.  
  7139.                                                 if(CheckAbort())
  7140.                                                 {
  7141.                                                     stopped = TRUE;
  7142.                                                     break;
  7143.                                                 }
  7144.  
  7145.                                                 /* Wait a little before retrying
  7146.                                                  * the locking operation. We add
  7147.                                                  * a little randomness here to
  7148.                                                  * reduce the likelihood of two
  7149.                                                  * competing processes trying to
  7150.                                                  * lock the same file at the
  7151.                                                  * same time.
  7152.                                                  */
  7153.  
  7154.                                                 numRandomTicks = ((TICKS_PER_SECOND / 2) * (rand() / 65536)) / randMax;
  7155.  
  7156.                                                 if(numRandomTicks > 0)
  7157.                                                     Delay(numRandomTicks);
  7158.                                             }
  7159.                                         }
  7160.                                         while(NOT locked);
  7161.  
  7162.                                         if(stopped)
  7163.                                         {
  7164.                                             SHOWMSG("lock polling loop stopped");
  7165.  
  7166.                                             DeleteFileLockNode(fln);
  7167.                                             fln = NULL;
  7168.  
  7169.                                             DeleteLockedRegionNode(lrn);
  7170.                                             lrn = NULL;
  7171.  
  7172.                                             UnLock(parentDir);
  7173.                                             parentDir = ZERO;
  7174.  
  7175.                                             errno = EINTR;
  7176.  
  7177.                                             raise(SIGINT);
  7178.                                         }
  7179.  
  7180.                                         if(locked)
  7181.                                         {
  7182.                                             SHOWMSG("the file now has a lock set");
  7183.                                             SET_FLAG(ufb->ufbflg,UFB_LOCKED);
  7184.                                             result = OK;
  7185.                                         }
  7186.                                     }
  7187.                                     else
  7188.                                     {
  7189.                                         SHOWMSG("couldn't read this file's name");
  7190.                                         MapIoErrToErrno();
  7191.                                     }
  7192.  
  7193.                                     UnLock(parentDir);
  7194.                                 }
  7195.                                 else
  7196.                                 {
  7197.                                     SHOWMSG("couldn't get a lock on the file's parent directory");
  7198.                                     MapIoErrToErrno();
  7199.                                 }
  7200.                             }
  7201.                             else if(cmd == F_SETLK)
  7202.                             {
  7203.                                 BOOL shared = (BOOL)(l->l_type == F_RDLCK);
  7204.                                 struct FileLockNode * existing_fln;
  7205.                                 BOOL locked = FALSE;
  7206.  
  7207.                                 if(shared)
  7208.                                     D(("this is a shared lock"));
  7209.                                 else
  7210.                                     D(("this is an exclusive lock"));
  7211.  
  7212.                                 lrn->lrn_Start    = start;
  7213.                                 lrn->lrn_Stop    = start+len-1;
  7214.                                 lrn->lrn_Shared    = shared;
  7215.  
  7216.                                 ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7217.  
  7218.                                 if(FindFileLockNodeByFileHandle(fileHandle,&existing_fln) == OK)
  7219.                                 {
  7220.                                     if(existing_fln != NULL)
  7221.                                     {
  7222.                                         SHOWMSG("that file is already locked by someone else");
  7223.  
  7224.                                         if(FindCollidingRegion(existing_fln,start,start+len-1,shared) == NULL)
  7225.                                         {
  7226.                                             SHOWMSG("but the locks don't collide");
  7227.  
  7228.                                             AddTail(&existing_fln->fln_LockedRegionList,(struct Node *)lrn);
  7229.                                             lrn = NULL;
  7230.  
  7231.                                             locked = TRUE;
  7232.                                         }
  7233.                                         else
  7234.                                         {
  7235.                                             SHOWMSG("and the locks collide");
  7236.                                         }
  7237.                                     }
  7238.                                     else
  7239.                                     {
  7240.                                         SHOWMSG("nobody has any locks on this file");
  7241.  
  7242.                                         AddTail(&SambaSemaphore->ss_FileLockList,(struct Node *)fln);
  7243.                                         AddTail(&fln->fln_LockedRegionList,(struct Node *)lrn);
  7244.  
  7245.                                         fln = NULL;
  7246.                                         lrn = NULL;
  7247.  
  7248.                                         locked = TRUE;
  7249.                                     }
  7250.                                 }
  7251.  
  7252.                                 ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7253.  
  7254.                                 if(locked)
  7255.                                 {
  7256.                                     SHOWMSG("the file now has a lock set");
  7257.  
  7258.                                     SET_FLAG(ufb->ufbflg,UFB_LOCKED);
  7259.  
  7260.                                     result = OK;
  7261.                                 }
  7262.                                 else
  7263.                                 {
  7264.                                     errno = EACCES;
  7265.                                 }
  7266.                             }
  7267.                             else if (cmd == F_GETLK)
  7268.                             {
  7269.                                 struct FileLockNode * fln;
  7270.                                 LONG error;
  7271.  
  7272.                                 SafeObtainSemaphoreShared((struct SignalSemaphore *)SambaSemaphore);
  7273.  
  7274.                                 SHOWMSG("checking for possible lock collision");
  7275.  
  7276.                                 error = FindFileLockNodeByFileHandle(fileHandle,&fln);
  7277.                                 if(error == OK)
  7278.                                 {
  7279.                                     if(fln != NULL)
  7280.                                     {
  7281.                                         struct LockedRegionNode * lrn;
  7282.                                         BOOL shared;
  7283.  
  7284.                                         SHOWMSG("somebody has locked this file");
  7285.  
  7286.                                         shared = (BOOL)(l->l_type == F_RDLCK);
  7287.  
  7288.                                         lrn = FindCollidingRegion(fln,start,start+len-1,shared);
  7289.                                         if(lrn != NULL)
  7290.                                         {
  7291.                                             SHOWMSG("there is a possible lock collision");
  7292.  
  7293.                                             l->l_type    = (lrn->lrn_Shared ? F_RDLCK : F_WRLCK);
  7294.                                             l->l_whence    = SEEK_SET;
  7295.                                             l->l_start    = lrn->lrn_Start;
  7296.                                             l->l_len    = lrn->lrn_Stop - lrn->lrn_Start + 1;
  7297.                                             l->l_pid    = lrn->lrn_Owner;
  7298.                                         }
  7299.                                         else
  7300.                                         {
  7301.                                             SHOWMSG("there is no lock collision");
  7302.  
  7303.                                             l->l_type = F_UNLCK;
  7304.                                         }
  7305.                                     }
  7306.                                     else
  7307.                                     {
  7308.                                         SHOWMSG("nobody has locked this file");
  7309.  
  7310.                                         l->l_type = F_UNLCK;
  7311.                                     }
  7312.  
  7313.                                     result = OK;
  7314.                                 }
  7315.                                 else
  7316.                                 {
  7317.                                     SetIoErr(error);
  7318.  
  7319.                                     MapIoErrToErrno();
  7320.                                 }
  7321.  
  7322.                                 ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7323.                             }
  7324.                         }
  7325.                         else
  7326.                         {
  7327.                             SHOWMSG("zero length lock/unlock");
  7328.                             result = OK;
  7329.                         }
  7330.                     }
  7331.                     else
  7332.                     {
  7333.                         SHOWMSG("invalid start/len");
  7334.                         SHOWVALUE(start);
  7335.                         SHOWVALUE(len);
  7336.                         errno = EINVAL;
  7337.                     }
  7338.                 }
  7339.                 else
  7340.                 {
  7341.                     SHOWMSG("couldn't determine start/len");
  7342.                     MapIoErrToErrno();
  7343.                 }
  7344.             }
  7345.             else
  7346.             {
  7347.                 SHOWMSG("couldn't get the bookkeeping memory needed");
  7348.                 MapIoErrToErrno();
  7349.             }
  7350.  
  7351.             DeleteFileLockNode(fln);
  7352.             DeleteLockedRegionNode(lrn);
  7353.         }
  7354.         else
  7355.         {
  7356.             SHOWMSG("invalid lock type or seek offset");
  7357.             SHOWVALUE(l->l_type);
  7358.             SHOWVALUE(l->l_whence);
  7359.             errno = EINVAL;
  7360.         }
  7361.     }
  7362.     else
  7363.     {
  7364.         SHOWMSG("no flock or no ufb");
  7365.         SHOWVALUE(l);
  7366.         SHOWVALUE(ufb);
  7367.  
  7368.         errno = EINVAL;
  7369.     }
  7370.  
  7371.     RETURN(result);
  7372.     return(result);
  7373. }
  7374.  
  7375. int
  7376. amiga_fcntl(int fd,int cmd,unsigned long arg)
  7377. {
  7378.     struct UFB * ufb;
  7379.     struct flock * l;
  7380.     int result = ERROR;
  7381.  
  7382.     chkabort();
  7383.  
  7384.     ENTER();
  7385.  
  7386.     /* Don't try to lock data in a socket... */
  7387.     ufb = chkufb(fd);
  7388.     if(ufb == NULL || FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7389.         ufb = NULL;
  7390.  
  7391.     l = (struct flock *)arg;
  7392.  
  7393.     switch(cmd)
  7394.     {
  7395.         /* Get the first lock that blocks the lock description pointed to
  7396.          * by the third argument, arg, taken as a pointer to a struct
  7397.          * flock (see above).  The information retrieved overwrites the
  7398.          * information passed to fcntl in the flock structure.  If no
  7399.          * lock is found that would prevent this lock from being created,
  7400.          * the structure is left unchanged by this function call except
  7401.          * for the lock type which is set to F_UNLCK.
  7402.          */
  7403.         case F_GETLK:
  7404.  
  7405.             SHOWMSG("F_GETLK");
  7406.             result = HandleFileLocking(cmd,l,ufb);
  7407.             break;
  7408.  
  7409.         /* Set or clear a file segment lock according to the lock de-
  7410.          * scription pointed to by the third argument, arg, taken as a
  7411.          * pointer to a struct flock (see above).    F_SETLK is used to es-
  7412.          * tablish shared (or read) locks (F_RDLCK) or exclusive (or
  7413.          * write) locks, (F_WRLCK), as well as remove either type of lock
  7414.          * (F_UNLCK). If a shared or exclusive lock cannot be set, fcntl
  7415.          * returns immediately with EACCES.
  7416.          */
  7417.         case F_SETLK:
  7418.  
  7419.             SHOWMSG("F_SETLK");
  7420.             result = HandleFileLocking(cmd,l,ufb);
  7421.             break;
  7422.  
  7423.         /* This command is the same as F_SETLK except that if a shared or
  7424.          * exclusive lock is blocked by other locks, the process waits
  7425.          * until the request can be satisfied.  If a signal that is to be
  7426.          * caught is received while fcntl is waiting for a region, the
  7427.          * fcntl will be interrupted if the signal handler has not speci-
  7428.          * fied the SA_RESTART (see sigaction(2)).
  7429.          */
  7430.         case F_SETLKW:
  7431.  
  7432.             SHOWMSG("F_SETLKW");
  7433.             result = HandleFileLocking(cmd,l,ufb);
  7434.             break;
  7435.  
  7436.         /* Get descriptor status flags, as described below (arg is ig-
  7437.          * noted).
  7438.          */
  7439.         case F_GETFL:
  7440.  
  7441.             SHOWMSG("F_GETFL");
  7442.             result = IsDescriptorNonblocking(fd) ? O_NONBLOCK : 0;
  7443.             break;
  7444.  
  7445.         /* Set descriptor status flags to arg. */
  7446.         case F_SETFL:
  7447.  
  7448.             SHOWMSG("F_SETFL");
  7449.             if(FLAG_IS_SET(arg,O_NONBLOCK))
  7450.                 BlockDescriptor(fd);
  7451.             else
  7452.                 UnblockDescriptor(fd);
  7453.  
  7454.             result = OK;
  7455.             break;
  7456.  
  7457.         default:
  7458.  
  7459.             D(("Unknown command %ld",cmd));
  7460.             errno = ENOSYS;
  7461.             break;
  7462.     }
  7463.  
  7464.     RETURN(result);
  7465.     return(result);
  7466. }
  7467.  
  7468. /******************************************************************************/
  7469.  
  7470. int
  7471. amiga_fgetc(FILE *in)
  7472. {
  7473.     struct UFB * ufb;
  7474.     int result = ERROR;
  7475.  
  7476.     PUSH_ASSERTS();
  7477.  
  7478.     chkabort();
  7479.  
  7480.     ufb = chkufb(fileno(in));
  7481.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7482.     {
  7483.         UBYTE c;
  7484.  
  7485.         ENTER();
  7486.         SHOWMSG("input from socket");
  7487.  
  7488.         if(recv(ufb->ufbfh,&c,1,0) == 1)
  7489.             result = c;
  7490.     }
  7491.     else
  7492.     {
  7493.         result = fgetc(in);
  7494.     }
  7495.  
  7496.     RETURN(result);
  7497.     POP();
  7498.     return(result);
  7499. }
  7500.  
  7501. char *
  7502. amiga_fgets(char *str,int n,FILE * in)
  7503. {
  7504.     struct UFB * ufb;
  7505.     char *result;
  7506.  
  7507.     ENTER();
  7508.  
  7509.     ufb = chkufb(fileno(in));
  7510.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7511.     {
  7512.         char *s = str;
  7513.         LONG rc;
  7514.         UBYTE c;
  7515.  
  7516.         SHOWMSG("input from socket");
  7517.         result = str;
  7518.  
  7519.         while(--n > 0)
  7520.         {
  7521.             chkabort();
  7522.  
  7523.             rc = recv(ufb->ufbfh,&c,1,0);
  7524.             if(rc == 1)
  7525.             {
  7526.                 (*str++) = c;
  7527.  
  7528.                 if(c == '\n')
  7529.                     break;
  7530.             }
  7531.             else
  7532.             {
  7533.                 /* End of stream or nothing read? */
  7534.                 if(rc < 0 || str == s)
  7535.                     result = NULL;
  7536.  
  7537.                 break;
  7538.             }
  7539.         }
  7540.  
  7541.         if(result != NULL)
  7542.             (*str) = '\0';
  7543.     }
  7544.     else
  7545.     {
  7546.         result = fgets(str,n,in);
  7547.     }
  7548.  
  7549.     RETURN(result);
  7550.     return(result);
  7551. }
  7552.  
  7553. int
  7554. amiga_fputs(const char *str,FILE *out)
  7555. {
  7556.     struct UFB * ufb;
  7557.     int result;
  7558.  
  7559.     chkabort();
  7560.  
  7561.     ENTER();
  7562.  
  7563.     ufb = chkufb(fileno(out));
  7564.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7565.     {
  7566.         SHOWMSG("output to socket");
  7567.  
  7568.         if(NOT STRING_IS_EMPTY(str))
  7569.             result = send(ufb->ufbfh,str,strlen(str),0);
  7570.         else
  7571.             result = OK;
  7572.  
  7573.         if(result == OK)
  7574.             result = send(ufb->ufbfh,"\n",1,0);
  7575.     }
  7576.     else
  7577.     {
  7578.         result = fputs(str,out);
  7579.     }
  7580.  
  7581.     RETURN(result);
  7582.     return(result);
  7583. }
  7584.  
  7585. int
  7586. amiga_puts(const char *str)
  7587. {
  7588.     int result;
  7589.  
  7590.     result = amiga_fputs(str,stdout);
  7591.  
  7592.     return(result);
  7593. }
  7594.  
  7595. int
  7596. amiga_vfprintf(FILE *out,const char *fmt,va_list args)
  7597. {
  7598.     struct UFB * ufb;
  7599.     int result;
  7600.  
  7601.     chkabort();
  7602.  
  7603.     ENTER();
  7604.  
  7605.     ufb = chkufb(fileno(out));
  7606.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7607.     {
  7608.         char buffer[1024];
  7609.  
  7610.         SHOWMSG("output to socket");
  7611.  
  7612.         vsnprintf(buffer,sizeof(buffer)-1,fmt,args);
  7613.         buffer[sizeof(buffer)-1] = '\0';
  7614.  
  7615.         if(NOT STRING_IS_EMPTY(buffer))
  7616.             result = send(ufb->ufbfh,buffer,strlen(buffer),0);
  7617.         else
  7618.             result = 0;
  7619.     }
  7620.     else
  7621.     {
  7622.         result = vfprintf(out,fmt,args);
  7623.     }
  7624.  
  7625.     RETURN(result);
  7626.     return(result);
  7627. }
  7628.  
  7629. int
  7630. amiga_fprintf(FILE *out,const char *fmt,...)
  7631. {
  7632.     va_list args;
  7633.     int result;
  7634.  
  7635.     va_start(args,fmt);
  7636.     result = amiga_vfprintf(out,fmt,args);
  7637.     va_end(args);
  7638.  
  7639.     return(result);
  7640. }
  7641.  
  7642. int
  7643. amiga_printf(const char *fmt,...)
  7644. {
  7645.     va_list args;
  7646.     int result;
  7647.  
  7648.     va_start(args,fmt);
  7649.     result = amiga_vfprintf(stdout,fmt,args);
  7650.     va_end(args);
  7651.  
  7652.     return(result);
  7653. }
  7654.  
  7655. size_t
  7656. amiga_fwrite(const void *data,size_t blockSize,size_t numBlocks,FILE *out)
  7657. {
  7658.     struct UFB * ufb;
  7659.     size_t result;
  7660.  
  7661.     chkabort();
  7662.  
  7663.     ENTER();
  7664.  
  7665.     ufb = chkufb(fileno(out));
  7666.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7667.     {
  7668.         SHOWMSG("output to socket");
  7669.  
  7670.         result = send(ufb->ufbfh,(APTR)data,blockSize * numBlocks,0);
  7671.         if(result > 0)
  7672.             result = (result/blockSize);
  7673.     }
  7674.     else
  7675.     {
  7676.         result = fwrite(data,blockSize,numBlocks,out);
  7677.     }
  7678.  
  7679.     RETURN(result);
  7680.     return(result);
  7681. }
  7682.  
  7683. size_t
  7684. amiga_fread(void *data,size_t blockSize,size_t numBlocks,FILE *in)
  7685. {
  7686.     struct UFB * ufb;
  7687.     size_t result;
  7688.  
  7689.     chkabort();
  7690.  
  7691.     ENTER();
  7692.  
  7693.     ufb = chkufb(fileno(in));
  7694.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7695.     {
  7696.         SHOWMSG("input from socket");
  7697.  
  7698.         result = recv(ufb->ufbfh,(APTR)data,blockSize * numBlocks,0);
  7699.         if(result > 0)
  7700.             result = (result/blockSize);
  7701.     }
  7702.     else
  7703.     {
  7704.         result = fread(data,blockSize,numBlocks,in);
  7705.     }
  7706.  
  7707.     RETURN(result);
  7708.     return(result);
  7709. }
  7710.  
  7711. int
  7712. amiga_fclose(FILE * stream)
  7713. {
  7714.     struct UFB * ufb;
  7715.     int result;
  7716.  
  7717.     chkabort();
  7718.  
  7719.     ENTER();
  7720.  
  7721.     ufb = chkufb(fileno(stream));
  7722.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7723.         result = OK;
  7724.     else
  7725.         result = fclose(stream);
  7726.  
  7727.     RETURN(result);
  7728.     return(result);
  7729. }
  7730.  
  7731. int
  7732. amiga_fflush(FILE * stream)
  7733. {
  7734.     struct UFB * ufb;
  7735.     int result;
  7736.  
  7737.     chkabort();
  7738.  
  7739.     ENTER();
  7740.  
  7741.     ufb = chkufb(fileno(stream));
  7742.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7743.         result = OK;
  7744.     else
  7745.         result = fflush(stream);
  7746.  
  7747.     RETURN(result);
  7748.     return(result);
  7749. }
  7750.  
  7751. int
  7752. amiga_fseek(FILE * stream,long int offset,int mode)
  7753. {
  7754.     struct UFB * ufb;
  7755.     int result;
  7756.  
  7757.     chkabort();
  7758.  
  7759.     ENTER();
  7760.  
  7761.     ufb = chkufb(fileno(stream));
  7762.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7763.         result = OK;
  7764.     else
  7765.         result = fseek(stream,offset,mode);
  7766.  
  7767.     RETURN(result);
  7768.     return(result);
  7769. }
  7770.  
  7771. long int
  7772. amiga_ftell(FILE * stream)
  7773. {
  7774.     struct UFB * ufb;
  7775.     long int result;
  7776.  
  7777.     chkabort();
  7778.  
  7779.     ENTER();
  7780.  
  7781.     ufb = chkufb(fileno(stream));
  7782.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7783.         result = 0;
  7784.     else
  7785.         result = ftell(stream);
  7786.  
  7787.     RETURN(result);
  7788.     return(result);
  7789. }
  7790.  
  7791. /******************************************************************************/
  7792.  
  7793. int
  7794. amiga_setvbuf(FILE *stream,char *buff,int type,size_t size)
  7795. {
  7796.     struct UFB * ufb;
  7797.     int result;
  7798.  
  7799.     chkabort();
  7800.  
  7801.     ENTER();
  7802.  
  7803.     ufb = chkufb(fileno(stream));
  7804.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7805.         result = OK;
  7806.     else
  7807.         result = setvbuf(stream,buff,type,size);
  7808.  
  7809.     RETURN(result);
  7810.     return(result);
  7811. }
  7812.  
  7813. /******************************************************************************/
  7814.  
  7815. int
  7816. amiga_fputc(int c,FILE *stream)
  7817. {
  7818.     struct UFB * ufb;
  7819.     int result = ERROR;
  7820.  
  7821.     chkabort();
  7822.  
  7823.     ENTER();
  7824.  
  7825.     ufb = chkufb(fileno(stream));
  7826.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7827.     {
  7828.         UBYTE oneByte = c;
  7829.  
  7830.         if(send(ufb->ufbfh,&oneByte,1,0) > 0)
  7831.             result = OK;
  7832.     }
  7833.     else
  7834.     {
  7835.         result = fputc(c,stream);
  7836.     }
  7837.  
  7838.     RETURN(result);
  7839.     return(result);
  7840. }
  7841.  
  7842. /******************************************************************************/
  7843.  
  7844. VOID
  7845. amiga_setbuf(FILE *stream,char *buffer)
  7846. {
  7847.     struct UFB * ufb;
  7848.  
  7849.     chkabort();
  7850.  
  7851.     ENTER();
  7852.  
  7853.     ufb = chkufb(fileno(stream));
  7854.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7855.     {
  7856.         /* Do nothing */
  7857.     }
  7858.     else
  7859.     {
  7860.         setbuf(stream,buffer);
  7861.     }
  7862.  
  7863.     LEAVE();
  7864. }
  7865.  
  7866. /******************************************************************************/
  7867.  
  7868. int
  7869. amiga_recv(int fd,void *buff,size_t nbytes,int flags)
  7870. {
  7871.     struct UFB * ufb;
  7872.     int result = ERROR;
  7873.  
  7874.     ENTER();
  7875.  
  7876.     ufb = chkufb(fd);
  7877.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7878.         result = recv(ufb->ufbfh,buff,nbytes,flags);
  7879.     else
  7880.         errno = EBADF;
  7881.  
  7882.     RETURN(result);
  7883.     return(result);
  7884. }
  7885.  
  7886. /******************************************************************************/
  7887.  
  7888. int
  7889. amiga_send(int fd,void *buff,size_t nbytes,int flags)
  7890. {
  7891.     struct UFB * ufb;
  7892.     int result = ERROR;
  7893.  
  7894.     ENTER();
  7895.  
  7896.     ufb = chkufb(fd);
  7897.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7898.         result = send(ufb->ufbfh,buff,nbytes,flags);
  7899.     else
  7900.         errno = EBADF;
  7901.  
  7902.     RETURN(result);
  7903.     return(result);
  7904. }
  7905.  
  7906. /******************************************************************************/
  7907.  
  7908. int
  7909. amiga_smbrun(char *cmd,char *outfile,BOOL shared)
  7910. {
  7911.     struct MangleInfo mi_cmd;
  7912.     struct MangleInfo mi_outfile;
  7913.     int result = ERROR;
  7914.  
  7915.     ENTER();
  7916.  
  7917.     ForbidDOS();
  7918.  
  7919.     if(outfile == NULL)
  7920.         outfile = "/dev/null";
  7921.  
  7922.     if(MangleName(&cmd,&mi_cmd) == OK)
  7923.     {
  7924.         if(MangleName(&outfile,&mi_outfile) == OK)
  7925.         {
  7926.             BPTR in;
  7927.  
  7928.             in = Open("NIL:",MODE_OLDFILE);
  7929.             if(in != ZERO)
  7930.             {
  7931.                 BPTR out;
  7932.  
  7933.                 out = Open(outfile,MODE_NEWFILE);
  7934.                 if(out != ZERO)
  7935.                 {
  7936.                     if(SystemTags(cmd,
  7937.                         SYS_Input,        in,
  7938.                         SYS_Output,        out,
  7939.                         SYS_UserShell,    TRUE,
  7940.                         NP_WindowPtr,    NULL,
  7941.                     TAG_DONE) != -1)
  7942.                     {
  7943.                         result = OK;
  7944.                     }
  7945.                     else
  7946.                     {
  7947.                         MapIoErrToErrno();
  7948.                     }
  7949.  
  7950.                     Close(out);
  7951.                 }
  7952.                 else
  7953.                 {
  7954.                     MapIoErrToErrno();
  7955.                 }
  7956.  
  7957.                 Close(in);
  7958.             }
  7959.             else
  7960.             {
  7961.                 MapIoErrToErrno();
  7962.             }
  7963.  
  7964.             UnmangleName(&outfile,&mi_outfile);
  7965.         }
  7966.  
  7967.         UnmangleName(&cmd,&mi_cmd);
  7968.     }
  7969.  
  7970.     PermitDOS();
  7971.  
  7972.     RETURN(result);
  7973.     return(result);
  7974. }
  7975.  
  7976. /******************************************************************************/
  7977.  
  7978. #define IFBSIZE 1024
  7979. #define max(a,b) ( (a) > (b) ? (a) : (b) )
  7980.  
  7981. int
  7982. amiga_get_interfaces(struct iface_struct * ifaces,int max_interfaces)
  7983. {
  7984.     struct ifreq * ifr_end;
  7985.     struct ifreq * ifr;
  7986.     struct ifconf * ifc;
  7987.     struct ifreq ifr_copy;
  7988.     int sockfd = -1;
  7989.     int result = -1;
  7990.     int total = 0;
  7991.     int len;
  7992.  
  7993.     /* Make room for the interface information. I hope
  7994.      * that 1024 bytes will be sufficient.
  7995.      */
  7996.     ifc = malloc(sizeof(*ifc) + IFBSIZE);
  7997.     if(ifc == NULL)
  7998.     {
  7999.         errno = ENOMEM;
  8000.         goto out;
  8001.     }
  8002.  
  8003.     sockfd = socket(AF_INET,SOCK_STREAM,0);
  8004.     if(sockfd < 0)
  8005.         goto out;
  8006.  
  8007.     /* Now attempt to copy the interface information into
  8008.      * the buffer. As of this writing, support for the
  8009.      * SIOCGIFCONF ioctl() action is undocumented in all
  8010.      * currently existing TCP/IP stacks. Nevertheless,
  8011.      * it appears to work.
  8012.      */
  8013.     ifc->ifc_len = IFBSIZE;
  8014.     ifc->ifc_buf = (char *)(ifc+1);
  8015.  
  8016.     if(IoctlSocket(sockfd,SIOCGIFCONF,(char *)ifc) != OK)
  8017.         goto out;
  8018.  
  8019.     len = ifc->ifc_len;
  8020.  
  8021.     ifr = (struct ifreq *)ifc->ifc_buf;
  8022.     ifr_end = (struct ifreq *)((char *)ifr + len);
  8023.  
  8024.     /* Now check each interface, extracting the interface
  8025.      * information.
  8026.      */
  8027.     while(ifr < ifr_end && total < max_interfaces)
  8028.     {
  8029.         ifr_copy = (*ifr);
  8030.  
  8031.         /* Try to obtain the address information. */
  8032.         if(IoctlSocket(sockfd,SIOCGIFADDR,(char *)&ifr_copy) == OK)
  8033.         {
  8034.             struct in_addr ipaddr;
  8035.  
  8036.             /* We need to remember this for later. */
  8037.             ipaddr = (*(struct sockaddr_in *)&ifr_copy.ifr_addr).sin_addr;
  8038.  
  8039.             /* And query the interface flags; in particular, we are interested
  8040.              * in whether this interface is currrently "up", i.e. "online".
  8041.              */
  8042.             if(IoctlSocket(sockfd,SIOCGIFFLAGS,(char *)&ifr_copy) == OK)
  8043.             {
  8044.                 if(ifr_copy.ifr_flags & IFF_UP)
  8045.                 {
  8046.                     /* And finally obtain the interface net mask. */
  8047.                     if(IoctlSocket(sockfd,SIOCGIFNETMASK,(char *)&ifr_copy) == OK)
  8048.                     {
  8049.                         struct in_addr nmask;
  8050.  
  8051.                         nmask = ((struct sockaddr_in *)&ifr_copy.ifr_addr)->sin_addr;
  8052.  
  8053.                         strncpy(ifaces[total].name, ifr_copy.ifr_name, sizeof(ifaces[total].name)-1);
  8054.                         ifaces[total].name[sizeof(ifaces[total].name)-1] = '\0';
  8055.  
  8056.                         ifaces[total].ip = ipaddr;
  8057.                         ifaces[total].netmask = nmask;
  8058.  
  8059.                         total++;
  8060.                     }
  8061.                 }
  8062.             }
  8063.         }
  8064.  
  8065.         len = max(sizeof(struct sockaddr),ifr->ifr_addr.sa_len);
  8066.         ifr = (struct ifreq *)(((char *)ifr) + sizeof(ifr->ifr_name) + len);
  8067.     }
  8068.  
  8069.     result = total;
  8070.  
  8071.  out:
  8072.  
  8073.     if(ifc != NULL)
  8074.         free(ifc);
  8075.  
  8076.     if(sockfd != -1)
  8077.         CloseSocket(sockfd);
  8078.  
  8079.     return(result);
  8080. }
  8081.